MyBatis⼀对⼀映射初识教程
MyBatis是⼀个⽀持普通SQL查询,存储过程和⾼级映射的优秀持久层框架。MyBatis消除了⼏乎所有的JDBC代码和参数的⼿⼯设置以及对结果集的检索封装。MyBatis可以使⽤简单的XML或注解⽤于配置和原始映射,将接⼝和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
⼀对⼀映射
在⽣活中,⼀对⼀的例⼦还是有的,⽐如啦,学⽣和⾝份证哦,或者在我国,实⾏的是⼀夫⼀妻制度哦。那么我们以学⽣和⾝份证每个学⽣只有⼀张⾝份证,⽽每张⾝份证的主⼈当然只有⼀个啦。
数据库脚本:
-- 删除数据库
drop database if exists mybaits;
-- 创建数据库
create database if not exists mybatis default character set utf8;
-
- 选择数据库
use mybatis;
-- 删除数据表
drop table if exists student ;
drop table if exists card;
-- 创建数据表
create table card(
cid int(255),
num varchar(18),
constraint pk_cid primary key (cid)
);
create table student(
sid int(255),
sname varchar(32),
scid int(255),
constraint pk_sid primary key (sid),
constraint fk_scid foreign key (scid) references card(cid)
);
-- 增加测试数据
insert into card (cid,num) values(1,'123456789012345678');
insert into student (sid,sname,scid) values(1,'哈哈',1);
新建⼀个one2one.Card.java类
package one2one;
import java.io.Serializable;
/**
* ⾝份证
* @author Administrator
*
*/
@SuppressWarnings("serial")
public class Card implements Serializable{
private Integer cid;
private String num;
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
}
新建one2one.Student.java类
package one2one;
import java.io.Serializable;
/**
* 学⽣
* @author Administrator
*
*/
@SuppressWarnings("serial")
public class Student implements Serializable{
private Integer sid;
private String sname;
private Card card;
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
}
在one2one包下新建l⽂件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN"
"/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cardNameSpace">
<resultMap type="one2one.Card" id="cardMap">
<id column="cid" property="cid"/>
<result column="num" property="num"/>
</resultMap>
</mapper>
同理,在one2one包下新建l⽂件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN"
"/dtd/mybatis-3-mapper.dtd">
<mapper namespace="studentNameSpace">
<resultMap type="one2one.Student" id="studentMap">
<id column="sid" property="sid"/>
<result column="sname" property="sname"/>
<!-- 关联字段不要写 -->
</resultMap>
<select id="findById" parameterType="integer" resultMap="studentMap">
drop table if exists admin
select s.sid,s.sname,c.cid,c.num
from student s,card c
where s.scid = c.cid and s.sid = #{sid}
</select>
</mapper>
在src下新建⼀个l⽂件,并包含l和l⽂件<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-////DTD Config 3.0//EN"
"/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 设置⼀个默认的环境信息 -->
<environments default="mysql_developer">
<!-- 连接MySQL环境信息 -->
<environment id="mysql_developer">
<!-- MyBatis使⽤jdbc事务管理器 -->
<transactionManager type="jdbc"/>
<!-- MyBatis使⽤连接池⽅式来获取连接对象 -->
<dataSource type="pooled">
<!-- 配置与数据库交互的4个必要属性 -->
<property name="driver" value="sql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="mysqladmin"/>
</dataSource>
</environment>
<!-- 连接Oracle环境信息 -->
<environment id="oracle_developer">
<!-- MyBatis使⽤jdbc事务管理器 -->
<transactionManager type="jdbc"/>
<!-- MyBatis使⽤连接池⽅式来获取连接对象 -->
<dataSource type="pooled">
<!-- 配置与数据库交互的4个必要属性 -->
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射⽂件 -->
<mappers>
<mapper resource="l"/>
<mapper resource="l"/>
</mappers>
</configuration>
在util包下新建⼀个⼯具类MyBatisUtil.java类
package util;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>(); public static SqlSessionFactory sqlSessionFactory ;
//私有化构造⽅法
private MyBatisUtil(){}
//加载位于src/l
static{
try {
Reader reader = ResourceAsReader("l"); sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SQLSession
* @return
*/
public static SqlSession getSqlSession(){
//从当前线程中获取SqlSession对象
SqlSession sqlSession = ();
if(sqlSession == null){
if(sqlSessionFactory != null){
sqlSession = sqlSessionFactory.openSession();
//讲sqlSession与当前线程绑定在⼀起
threadLocal.set(sqlSession);
}
}
return sqlSession;
}
/**
* 关闭SqlSession 并与当前线程分开
*/
public static void closeSqlSession(){
//从当前线程中获取SqlSession对象
SqlSession sqlSession = ();
//如果SqlSession对象⾮空
if(sqlSession != null){
//关闭SqlSession对象
sqlSession.close();
//分离当前线程与SqlSession的关系
}
}
//测试
public static void main(String[] args) {
SqlSession sqlSession = SqlSession();
Connection conn= Connection();
System.out.println(conn != null ?"连接成功":"连接失败");
}
}
新建持久层类StuentCardDAO.java类
package one2one;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import util.MyBatisUtil;
/**
* 持久层
* @author Administrator
*
*/
public class StudentCardDAO {
/**
* 查询1号学⽣的信息与⾝份证信息
* @param id
* @return
* @throws Exception
*/
public Student findById(Integer id) throws Exception{
SqlSession sqlSession = null;
try {
sqlSession = SqlSession();
return sqlSession.selectOne("studentNameSpace.findById", id);
} catch (Exception e) {
e.printStackTrace();
throw e;
}finally{
MyBatisUtil.closeSqlSession();
}
}
//测试查询1号学⽣的信息与⾝份证信息
@Test
public void testFindById() throws Exception{
StudentCardDAO dao = new StudentCardDAO();
Student student = dao.findById(1);
System.out.Sid()+":"+Sname() }
}
这时我们只能查询1号学⽣的姓名,但是我们不能去查询它的⾝份号号,因为此时的card属性的值为null,从l中可以看出
<select id="findById" parameterType="integer" resultMap="studentMap">
MyBatis在解析这⼀句的时候只能将查询的数据封装到sid,sname中,所以怎么办?
在l中的
<resultMap type="one2one.Card" id="cardMap">
<id column="cid" property="cid"/>
<result column="num" property="num"/>
</resultMap>
增加
<!--
引⼊l⽂件中的映射信息
property表⽰Student的关联属性
-->
<association property="card" resultMap="cardNameSpace.cardMap"/>
那么此时的l的完整内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN"
"/dtd/mybatis-3-mapper.dtd">
<mapper namespace="studentNameSpace">
<resultMap type="one2one.Student" id="studentMap">
<id column="sid" property="sid"/>
<result column="sname" property="sname"/>
<!--
引⼊l⽂件中的映射信息
property表⽰Student的关联属性
-->
<association property="card" resultMap="cardNameSpace.cardMap"/>
</resultMap>
<select id="findById" parameterType="integer" resultMap="studentMap">
select s.sid,s.sname,c.cid,c.num
from student s,card c
where s.scid = c.cid and s.sid = #{sid}
</select>
</mapper>
现在可以测试学⽣的⾝份证号码了
将持久层类StuentCardDAO.java类的测试⽅法改为
//测试查询1号学⽣的信息与⾝份证信息
@Test
public void testFindById() throws Exception{
StudentCardDAO dao = new StudentCardDAO();
Student student = dao.findById(1);
System.out.Sid()+":"+Sname()+":"+Card().getNum());
}
同理
在StudentDAO.java类中增加查询“哈哈”学⽣的信息与⾝份证信息的⽅法
/**
* 查询“哈哈”学⽣的信息与⾝份证信息
* @param name
* @return
* @throws Exception
*/
public Student findByName(String name) throws Exception{
SqlSession sqlSession = null;
try {
sqlSession = SqlSession();
return sqlSession.selectOne("studentNameSpace.findByName", name);
} catch (Exception e) {
e.printStackTrace();
throw e;
}finally{
MyBatisUtil.closeSqlSession();
}
}
并增加测试⽅法哦
//测试查询“哈哈”学⽣的信息与⾝份证信息
@Test
public void testFindByName() throws Exception{
StudentCardDAO dao = new StudentCardDAO();
Student student = dao.findByName("哈哈");
System.out.Sid()+":"+Sname()+":"+Card().getNum());
}
当然如果你现在就测试,你会死的很惨,因为你没有在l⽂件中配置<select>哦,所以在l ⽂件中增加<select>配置信息
<select id="findByName" parameterType="string" resultMap="studentMap">
select s.sid,s.sname,c.cid,c.num
from student s,card c
where s.scid = c.cid and s.sname = #{sname}
</select>
这样就可以测试成功了。⼤功告成。
完整代码如下: