网上得来终觉浅,绝知此事要躬行。
这两个比较简单,就放在这里一起学习理解了。
一、SqlSession学习
在MyBatis中,SqlSession是其核心接口。在MyBatis中有两个实现类,DefaultSqlSession和SqlSessionManager。DefaultSqlSession是单线程使用的,而SqlSessionManager在多线程环境下使用。SqlSession的作用类似于一个JDBC中的Connection对象,代表这一个连接的资源。具体而言,它的作用有3个:
先来掌握它的创建方法,有了SqlSessionFactory创建的SqlSession就非常简单了,如下所示:
SqlSession sqlSession = SqlSessionFactory.openSession();
注意:SqlSession只是一个门面接口,它有很多方法,可以直接发送SQL。它就好像一家软件公司的商务人员,是一个门面,而实际干活的是软件工程师。在MyBatis中,真正干活的是Executor,我们活在底层看到它(后面会分析学习)。
SqlSession控制数据库事务的方法,如下所示:
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
//do something
sqlSession.commit();//提交事务
} catch (Exception e) {
sqlSession.rollback();//回滚事务
}
这里使用commit方法提交事务,或者使用rollback方法回滚事务。因为它代表这一个数据库的连接资源。使用后要及时的关闭它。如果不关闭,那么数据库的连接资源就会很快被消费光,整个系统就会陷入瘫痪状态,所以使用finally语句来保证其顺利关闭。
二、Mapper的两种实现方式
前提:我们先准备数据库表和实体类(后面都要用到)。
emp.sql:
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`empno` int(20) DEFAULT NULL,
`deptno` int(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES ('1', '张三', '1000', '10');
INSERT INTO `emp` VALUES ('2', '李四', '1001', '20');
INSERT INTO `emp` VALUES ('3', '王五', '1002', '30');
INSERT INTO `emp` VALUES ('4', '赵六', '1003', '40');
INSERT INTO `emp` VALUES ('5', '小星星', '1004', '20');
INSERT INTO `emp` VALUES ('6', '大猩猩', '1005', '30');
dept.sql:
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`deptno` int(10) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES ('1', '10', '人事部');
INSERT INTO `dept` VALUES ('2', '20', '科技部');
INSERT INTO `dept` VALUES ('3', '30', '测试部');
INSERT INTO `dept` VALUES ('4', '40', '运维部');
两个实体类自己创建一下:emp.java和dept.java。
开工喽-----------------------------------------------------------------------------------------------------------------------------
①. 用xml实现映射器(比较常用)
public interface EmpMapper {
//用id来查询员工
Emp getEmpById(int id);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.littlestar.mapper.EmpMapper">
<select id="getEmpById" parameterType="int" resultType="com.littlestar.entity.Emp">
select * from emp where id = #{id}
</select>
</mapper>
2.非常重要的一点!!!,在mybatis-config.xml配置文件引入这一段:
<mappers>
<mapper resource="com/littlestar/mapper/EmpMapper.xml"></mapper>
</mappers>
有了这几个文件,就完成了一个映射器的定义。xml文件还算比较简单,我们稍微讲解一下:
注意,我们并没有配置SQL执行和emp的对应关系,select * 和 Emp是如何映射的那?其实这里采用的是一种被称为自动映射的功能。MyBatis在默认情况下提供自动映射的,只要SQL返回的列名和entity下面的属性名对应即可(一句话,就是列名=属性名)。
②. 注解实现映射器(比较简单而且帅)
//查询部门编号为20的员工
@Select("Select * from emp where deptno = #{deptno} ")
List<Emp> getEmpsByDeptno(int deptno);
<mappers>
<mapper class="com.littlestar.mapper.EmpMapper"></mapper>
</mappers>
当然也不要忘记我们还有一种代码配置方式啊:configuration.addMapper(EmpMapper.class);
另外非常重要的一点:不要同时配置EmpMapper.xml和EmpMapper.java。虽然实际开发中不可能出现,但是初学者容易出现这样的问题。
现在SqlSession已经实现好了,还剩什么?当时是执行方法了(卧槽,终于可以看到执行结果了?)
不过,这里又分两种,第一种:用SqlSession发送SQL 第二种:用Mapper接口发送SQL
使用单元测试爽一下:
package mappertest;
import com.littlestar.entity.Emp;
import com.littlestar.mapper.EmpMapper;
import com.littlestar.util.SqlSessionFactoryUtil;
import com.littlestar.util.SqlSessionFactoryUtil2;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Before;
import org.junit.Test;
/**
* 用来测试EmpMapper
*/
public class TestEmpMapper {
private SqlSessionFactory sqlSessionFactory = null;
//初始化sqlSessionFactory
@Before
public void setSqlSessionFactory() {
sqlSessionFactory = SqlSessionFactoryUtil2.getSqlSessionFactory();
}
//测试Mapper接口发送sql
@Test
public void getEmpByIdTest() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpById(1);
System.out.println(emp.getName());
}
}
//测试sqlSession发送sql
@Test
public void getEmpByIdTest2() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
Emp emp = (Emp) sqlSession.selectOne("com.littlestar.mapper.EmpMapper.getEmpById", 1);
System.out.println(emp.getName());
}
}
//测试 @select 注解方式
@Test
public void getEmpsByDeptnoTest() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> emps = empMapper.getEmpsByDeptno(20);
for (Emp emp : emps) {
System.out.println(emp.getName());
}
}
}
}
注意,我们再想想,既然已经有SqlSession能够发送SQL,那为什么还要一个Mapper接口那?
另外一个小细节:
配置文件中我配置xml同样是可以使用注解的,说明配置了EmpMapper.xml其实也就初始化了EmpMapper.java。
下一节:组件的生命周期