1.MyBetis环境搭建
1.1新建项目
新建java项目或web 项目。
1.2 导入JAR包
导入mybatis和数据库驱动包、日志包(配置日志配置文件)。
1.3创建myBatis-config.xml
(可以参考用户手册)。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--可以设置多个运行环境,满足不同需要,例如 开发、测试、生产环境上有不同一配置 -->
<environments default="development">
<environment id="development">
<!--事务管理类型主要有jdbc和managed,前者依赖于数据源获得的连接,后者依赖于容器 -->
<transactionManager type="JDBC" />
<!-- type="POOLED"表示使用连接池, type="UNPOOLED"表示不使用连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<!-- 如果数据库设置为UTF-8,则URL参数连接需要添加?useUnicode=true&characterEncoding=UTF-8,如下 -->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
</configuration>
1.4创建数据库及表
drop database if exists mybatis;
create database mybatis CHARACTER SET UTF8;
use mybatis;
create table dept(
dept_id int primary key auto_increment,
dept_name varchar(50),
dept_address varchar(50)
);
insert into dept(dept_name,dept_address) values('研发部一部','广州');
insert into dept(dept_name,dept_address) values('研发部二部','广州');
insert into dept(dept_name,dept_address) values('研发部三部','深圳');
select * from dept;
1.5创建实体类:Dept.java
public class Dept implements Serializable {
private Integer deptId; //部门编号
private String deptName;//部门名称
private String deptAddress;//部门地址
1.6创建SQL映射文件及修改主配置文件
SQL映射文件:DeptMapper.xml(可以参考用户手册)
<?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="cn.itcast.entity.DeptMapper">
<!-- 一般在查询时使用--><!-- type指定的是对应的实体类 -->
<resultMap type="cn.itcast.entity.Dept" id="deptResultMap">
<!-- id用来配置表的主键与类的属性的映射关系 ,column指定的是表的字段名; property指定的是类的属性名-->
<id property="deptId" column="dept_id"/>
<!-- result用来配置 普通字段与类的属性的映射关系 ,column指定的是表的字段名; property指定的是类的属性名-->
<result property="deptName" column="dept_name"/>
<result property="deptAddress" column="dept_address"/>
</resultMap>
<!-- 定义插入的sql语句,通过命名空间+id方式被定位 -->
<insert id="insertDept" parameterType="cn.itcast.entity.Dept">
<!-- #{} 用来获取传过来的参数 -->
insert into dept(dept_name,dept_address) values(#{deptName},#{deptAddress});
</insert>
</mapper>
修改myBatis-config.xml,加入映射文件信息
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
…………
</environments>
<mappers>
<mapper resource="cn/itcast/entity/DeptMapper.xml" />
</mappers>
</configuration>
1.7编写数据库操作
包括操作接口及实现,接口略,实现类为:DeptDaoImpl.java
public class DeptDaoImpl {
/**
* 用于插入数据到dept表。
* @param dept 部门信息
* @return 表示受影响的行数
*/
public int insert(Dept dept){
/*
* 1.读取配置信息
* 2.构建session工厂
* 3.创建session
* 4.启动事务(可选)
* 5.数据处理
* 6.提交事务、回滚事务(可选)
* 7.关闭session
*/
int i=0;
SqlSession session=null;
String config="myBatis-config.xml";
Reader reader = null;
try {
reader=Resources.getResourceAsReader(config);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
session=sqlSessionFactory.openSession();
//事务默认自动启动
//(SQL映射文件定义的命名空间.SQL语句的ID)定位SQL语句,例如下的:cn.itcast.entity.DeptMapper.insertDept
i=session.insert("cn.itcast.entity.DeptMapper.insertDept",dept);
session.commit();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
session.rollback();
}finally{
//关闭reader对象,这里略
session.close();
}
return i;
}
}
1.8编写测试类
需要导入junit包
public class DeptTest {
private static DeptDaoImpl deptDaoImpl;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
deptDaoImpl=new DeptDaoImpl();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
deptDaoImpl=null;
}
@Test
public void testInsert() {
Dept dept=new Dept();
dept.setDeptName("市场部");
dept.setDeptAddress("深圳");
int i=deptDaoImpl.insert(dept);
System.out.println("受影响行数:"+i);
}
}
2.基本的CRUD操作
2.1别名与自定义别名
2.1.1 内置别名
对常用的 java 类型,已经内置了一些别名支持。这些别名都是不区分大小写的。(详细参看用户手册)
2.1.2 自定义别名
在myBatis的主配置文件给cn.itcast.entity.Dept类创建别名Dept,后继的DeptMapper.xml配置文件中可以使用别名
<!-- 通过别名简化对类的使用 -->
<typeAliases>
<typeAlias type="cn.itcast.entity.Dept" alias="Dept" />
</typeAliases>
2.2 MyBatisUtil工具类
public class MyBatisUtil {
private static final ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
private static SqlSessionFactory sessionFactory;
private static String CONFIG_FILE_LOCATION = "myBatis-config.xml";
static {
try {
buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
/**
* Returns the ThreadLocal Session instance. Lazy initialize
* the <code>SessionFactory</code> if needed.
* @return Session
* @throws Exception
*/
public static SqlSession getSession() throws Exception {
SqlSession session = (SqlSession) threadLocal.get();
if (session == null) {
if (sessionFactory == null) {
buildSessionFactory();
}
session = (sessionFactory != null)?sessionFactory.openSession():null;
threadLocal.set(session);
}
return session;
}
// build session factory
public static void buildSessionFactory() {
Reader reader=null;
try {
reader=Resources.getResourceAsReader(CONFIG_FILE_LOCATION);
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}finally{
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// Close the single session instance.
public static void closeSession(){
SqlSession session = (SqlSession) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
// return session factory
public static SqlSessionFactory getSessionFactory() {
return sessionFactory;
}
}
2.3 CRUD操作
1)新增操作
配置文件DeptMapper.xml使用别名, DeptDaoImpl.java新增方法使用工具类。
修改配置文件DeptMapper.xml(使用别名):
<!--parameterType="Dept"不写时,也能自动根据代码传递的参数自动匹配-->
<insert id="insert" parameterType="Dept">
insert into dept(dept_name) values(#{deptName});
</insert>
2)修改操作
修改配置文件deptMapper.xml,添加
<update id="update" parameterType="Dept">
update dept set dept_name=#{deptName} ,dept_address=#{deptAddress} where dept_id=#{deptId}
</update>
3)删除操作
修改配置文件deptMapper.xml,添加
<delete id="delete" parameterType="Dept">
delete from dept where dept_id=#{deptId}
</delete>
4)查询操作(返回单条记录)
配置deptMapper.xml文件的resultMap元素及SQL查询语句
<!—返回单条记录,表字段和对应实体属性命名一致时可以不使用resultMap属性配置,直接使用resultType="返回的全类名或别名",建议使用前者;查询结果为所有字段时,也可以用*表示 -->
<select id="selectOne" parameterType="int" resultMap="deptResultMap" >
select dept_id, dept_name from dept where dept_id=#{deptId}
</select>
5)查询操作(返回多条记录)
修改配置文件deptMapper.xml,添加
<!-- 返回多条记录,返回结果配置的不是集合类型,而是集合元素的类型;参数也可以通过Map等方式封装 -->
<select id="selectList" parameterType="Map" resultMap="deptResultMap">
select * from dept where dept_name like #{deptName}
</select>
3.动态SQL操作
3.1准备工作
创建表及库,实体类,配置文件(参考上章节内容),以下为建表和库的SQL:
3.2 IF语句
修改配置文件deptMapper.xml,添加
<!-- 动态IF条件 -->
<select id="selectListUseIf" parameterType="Dept" resultMap="deptResultMap">
select * from dept where 1=1
<if test="deptId!=null">
and dept_id=#{deptId}
</if>
<if test="deptName!=null">
and dept_name=#{deptName}
</if>
<if test="deptAddress!=null">
and dept_address=#{deptAddress}
</if>
</select>
3.3 WHERE语句
修改配置文件deptMapper.xml,添加
<!-- 动态Where条件 ,一般也需要与if结合使用,与纯if比较,省略了where 1=1-->
<select id="selectListUseWhere" parameterType="Dept" resultMap="deptResultMap">
select * from dept
<where>
<if test="deptId!=null">
and dept_id=#{deptId}
</if>
<if test="deptName!=null">
and dept_name=#{deptName}
</if>
<if test="deptAddress!=null">
and dept_address=#{deptAddress}
</if>
</where>
</select>
3.4 choose(when,otherwise)语句
修改配置文件deptMapper.xml,添加
<select id="selectListUseChoose" parameterType="Dept" resultMap="deptResultMap">
select * from dept where 1=1
<choose>
<when test="deptId!=null">and dept_id=#{deptId}</when>
<when test="deptName!=null">and dept_name=#{deptName}</when>
<when test="deptAddress!=null">and dept_address=#{deptAddress}</when>
<otherwise>and !1 = 1</otherwise>
</choose>
</select>
3.5 SET语句
修改配置文件deptMapper.xml,添加
<!--动态set语句可以用来更新数据 -->
<update id="updateUseSet" parameterType="Dept">
update dept
<set>
<if test="deptName!=null">dept_name=#{deptName},</if>
<if test="deptAddress!=null">dept_address=#{deptAddress},</if>
</set>
where dept_id=#{deptId}
</update>
3.6 ForEach语句
批量更新:需要修改mybatis-config.xml文件相关数据库连接的信息(主要红色部分)
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true" />
< <!-- 定义根据多个部门ID查询部门相关部门信息的SQL语句 ,resultMap的值是指集合里元素的类型,parameterType不用指定 -->
<select id="selectListUseForeach" parameterType="Integer[]" resultMap="deptResultMap">
select * from dept where dept_id in
<!-- collection="array或list",array用来对应参数为数组,list对应参数为 集合 -->
<foreach collection="array" item="deptId" open="(" separator="," close=")">
#{deptId}
</foreach>
</select>
3.7 include语句
修改配置文件deptMapper.xml,添加
<!-- 使用include语句动态插入表的字段及对应的值 -->
<sql id="key">
<!--suffixOverrides="," 可以忽略最后“,”号 -->
<trim suffixOverrides=",">
<if test="deptName!=null">
dept_name,
</if>
<if test="deptAddress!=null">
dept_address,
</if>
</trim>
</sql>
<sql id="value">
<trim suffixOverrides="," >
<if test="deptName!=null">
#{deptName},
</if>
<if test="deptAddress!=null">
#{deptAddress},
</if>
</trim>
</sql>
使用include语句:
<insert id="insertUseInclude" parameterType="Dept">
insert into dept(<include refid="key" />) values(<include refid="value"/>)
</insert>
4.关联查询
4.1准备工作
1)创建项目并导入包
2)配置myBatis-config.xml
3)创建数据库及表:
drop database if exists mybatis;
create database mybatis CHARACTER SET UTF8;
use mybatis;
create table dept(
dept_id int primary key auto_increment,
dept_name varchar(50),
dept_address varchar(50)
);
create table emp(
emp_id varchar(18) primary key,
emp_name varchar(50),
emp_sex char(1),
dept_id int
);
insert into dept(dept_name,dept_address) values('研发部一部','广州');
insert into dept(dept_name,dept_address) values('研发部二部','广州');
insert into dept(dept_name,dept_address) values('研发部三部','深圳');
insert into emp(emp_id,emp_name,emp_sex,dept_id) values('44152199507052110','张大',"男","1");
insert into emp(emp_id,emp_name,emp_sex,dept_id) values('44152199507052111','张一',"女","1");
insert into emp(emp_id,emp_name,emp_sex,dept_id) values('44152199507052112','张二',"男","1");
select * from dept;
select * from emp;
4.2 基于association查询(用于多对一或一对一)
4.2.1 创建实体类:Dept.java/Emp.java
部门实体类:Dept.java
public class Dept implements Serializable{
private String deptAddress;
private String deptName;
private Integer deptId;
员工实体类:Emp.java
public class Emp implements Serializable{
private String empId;
private String empName;
private String empSex;
private Dept dept;
4.2.2 配置DeptMapper.xml/EmpMapper.xml
(重点加入级联的查询语句),并映射文件信息到mybatis-config.xml中:
DeptMapper.xml
<mapper namespace="cn.itcast.entity.DeptMapper">
<!-- 表字段和对应实体属性命名一致时可以不配置 -->
<resultMap id="deptResultMap" type="Dept">
<id property="deptId" column="dept_id" />
<result property="deptName" column="dept_name" />
<result property="deptAddress" column="dept_address" />
</resultMap>
</mapper>
EmpMapper.xml,配置多对一的关联
<mapper namespace="cn.itcast.entity.EmpMapper">
<!-- 表字段和对应实体属性命名一致时可以不配置 -->
<resultMap id="empResultMap" type="Emp">
<id property="empId" column="emp_id" />
<result property="empName" column="emp_name" />
<result property="empSex" column="emp_sex" />
<!-- association配置对一关联 -->
<association property="dept" column="dept_id" javaType="Dept" resultMap="cn.itcast.entity.DeptMapper.deptResultMap" />
</resultMap>
<!--根据部门名称查询员工(包括员工所在部门)信息 -->
<select id="selectEmpDeptList" parameterType="Emp" resultMap="empResultMap">
<!-- 访问emp.dept.deptName, 前面不用写emp, 直接写 dept.deptName-->
select e.*,d.* from emp e inner join dept d on
e.dept_id=d.dept_id where d.dept_name like #{dept.deptName}
</select>
</mapper>
4.2.3 配置文件myBatis-config.xml
<!-- 通过别名简化对类的使用 -->
<typeAliases>
<typeAlias type="cn.itcast.entity.Dept" alias="Dept" />
<typeAlias type="cn.itcast.entity.Emp" alias="Emp" />
</typeAliases>
…….
<!--导入SQL映射文件 -->
<mappers>
<mapper resource="cn/itcast/entity/DeptMapper.xml" />
<mapper resource="cn/itcast/entity/EmpMapper.xml" />
</mappers>
4.2.4 编写EmpDaoImpl.java实现查询
public class EmpDaoImpl {
SqlSession session;
public List<Emp> selectEmpDeptList(Emp emp){
List<Emp> emps=null;
try{
session=MyBatisUtil.getSession();
emps=session.selectList("cn.itcast.entity.EmpMapper.selectEmpDeptList",emp);
//session.commit();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
//session.rollback();
}finally{
MyBatisUtil.closeSession();
}
return emps;
}
}
4.2.5 编写测试类
EmplTest.java
@Test
public void selectEmpDeptList() {
Emp emp=new Emp();
Dept dept=new Dept();
dept.setDeptName("%研%");
emp.setDept(dept);
List<Emp> emps=empDaoImpl.selectEmpDeptList(emp);
for(Emp emp1:emps){
System.out.println("emp="+emp1);
//System.out.println("dept="+emp1.getDept());
}
}
4.3 基于collection查询(用于一对多或多对多)
1)编写 Dept.java/Emp.java实体类
Dept.java
public class Dept implements Serializable{
private String deptAddress;
private String deptName;
private Integer deptId;
private List<Emp> emps;
//省略set和get方法
Emp.java
public class Emp implements Serializable{
private String empId;
private String empName;
private String empSex;
//省略set和get方法
2)配置DeptMapper.xml
DeptMapper.xml文件,配置resultMap(重点是collection配置)和查询SQL语句:
<mapper namespace="cn.itcast.entity.DeptMapper">
<!-- 表字段和对应实体属性命名一致时可以不配置 -->
<resultMap id="deptResultMap" type="Dept">
<id property="deptId" column="dept_id" />
<result property="deptName" column="dept_name" />
<result property="deptAddress" column="dept_address" />
<!-- collection中resultMap引用的是其它文件的map 需要命名空间+id,例如:cn.itcast.entity.EmpMapper.empResultMap -->
<collection property="emps" ofType="Emp" resultMap="cn.itcast.entity.EmpMapper.empResultMap"/>
</resultMap>
<select id="selectDeptEmpList" parameterType="Dept" resultMap="deptResultMap">
select d.*, e.* from dept d inner join emp e on d.dept_id=e.dept_id where d.dept_name like #{deptName}
</select>
</mapper>
4.4 一对多双向关联查询示例
4.4.1 编写实体类:Dept.java/Emp.java
Dept.java
public class Dept implements Serializable{
private String deptAddress;
private String deptName;
private Integer deptId;
private List<Emp> emps;
//省略set和get方法
Emp.java
public class Emp implements Serializable{
private String empId;
private String empName;
private String empSex;
private Dept dept;
//省略set/get方法
4.4.2 编写DeptMapper.xml/EmpMapper.xml文件
DeptMapper.xml
<?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="cn.itcast.entity.DeptMapper">
<!-- 表字段和对应实体属性命名一致时可以不配置 -->
<resultMap id="deptResultMap" type="Dept">
<id property="deptId" column="dept_id" />
<result property="deptName" column="dept_name" />
<result property="deptAddress" column="dept_address" />
</resultMap>
<!-- 一对多时,“多”的关联属性可独立配置resultMap,采用extends继承基本属性的resultMap -->
<resultMap id="deptExtResultMap" type="Dept" extends="deptResultMap">
<!-- collection中resultMap引用的是其它文件的map 需要命名空间+id,例如:cn.itcast.entity.EmpMapper.empResultMap -->
<collection property="emps" ofType="Emp"
resultMap="cn.itcast.entity.EmpMapper.empResultMap" />
</resultMap>
<!--用于部门和员工关联查询,返回部门信息(包含部门员工信息)列表,采用extends继承基本属性的resultMap -->
<select id="selectDeptEmpList" parameterType="Dept" resultMap="deptExtResultMap">
select d.*, e.* from dept d inner join emp e on d.dept_id=e.dept_id
where d.dept_name like #{deptName}
</select>
</mapper>
EmpMapper.xml
<?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="cn.itcast.entity.EmpMapper">
<!-- 表字段和对应实体属性命名一致时可以不配置 -->
<resultMap id="empResultMap" type="Emp">
<id property="empId" column="emp_id" />
<result property="empName" column="emp_name" />
<result property="empSex" column="emp_sex" />
<!--注意association元素的resultMap的值为没有配置“多”的属性映射的deptResultMap,如下 -->
<association property="dept" column="dept_id" resultMap="cn.itcast.entity.DeptMapper.deptResultMap"/>
</resultMap>
<!-- 用于员工和部门关联查询,返回员工信息(包含部门信息)列表 -->
<select id="selectEmpDeptList" parameterType="Emp" resultMap="empResultMap">
select e.*,d.* from emp e inner join dept d on
e.dept_id=d.dept_id where d.dept_name like #{dept.deptName}
</select>
</mapper>
4.4.3 编写数据操作类:DeptDaoImpl.java/EmpDaoImpl.java
DeptDaoImpl.java,查询部门员工信息,返回类型为List<Dept>,关键代码:
public List<Dept> selectDeptEmpList(Dept dept){
SqlSession session=null;
List<Dept> deps=null;
try{
session=MyBatisUtil.getSession();
deps=session.selectList("cn.itcast.entity.DeptMapper.selectDeptEmpList",dept);
session.commit();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
session.rollback();
}finally{
MyBatisUtil.closeSession();
}
return deps;
}
EmpDaoImpl.java
查询员工及其所在部门信息,返回类型为List< Emp >,关键代码
public List<Emp> selectEmpDeptList(Emp emp){
SqlSession session=null;
List<Emp> emps=null;
try{
session=MyBatisUtil.getSession();
emps=session.selectList("cn.itcast.entity.EmpMapper.selectEmpDeptList",emp);
session.commit();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
session.rollback();
}finally{
MyBatisUtil.closeSession();
}
return emps;
}
4.4.4 编写测试类:DeptTest.java/EmpTest.java
DeptTest.java关键代码
//测试部门和员工的关联查询,并遍历装载部门类型的结果集
@Test
public void selectDeptEmpList() {
Dept paramDept=new Dept();
paramDept.setDeptName("%研%");
List<Dept> depts=deptDaoImpl.selectDeptEmpList(paramDept);
for(Dept dept:depts){
System.out.println("dept:"+dept);
}
}
EmpTest.java关键代码
//测试员工和部门的关联查询,并遍历装载员工类型的结果集
@Test
public void selectEmpDeptList() {
Emp emp=new Emp();
Dept dept=new Dept();
dept.setDeptName("%研%");
emp.setDept(dept);
List<Emp> emps=empDaoImpl.selectEmpDeptList(emp);
for(Emp emp1:emps){
System.out.println("emp="+emp1);
System.out.println("dept="+emp1.getDept());
}
}
5. 缓存
Mybatis和hibernate一样,也使用缓存;缓存分为一级缓存和二级缓存,一级缓存指在SqlSession内;二级缓存能被所有的SqlSession共享。默认开启一级缓存,不启用二级缓存。
配置:
使用二级缓存机制:需要开启全局缓存,文件级缓存(默认没有开启) ,语句级缓存,才能使用二级缓存。
5.1 全局缓存配置
在mybatis的主配置文件中进行配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 默认有启用全局缓存的,禁用可以把value设为false,如果这里设为false,Mapper.xml或SQL语句级的缓存配置不再起作用 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!—省略其它配置信息 -->
</configuration>
5.2 Mapper文件级缓存配置
<?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="cn.itcast.entity.DeptMapper">
<!--
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="false"/>
创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。可用的收回策略有以下几种, 默认的是 LRU:
eviction:缓存策略
1. LRU – 最近最少使用的:移除最长时间不被使用的对象(默认)。
2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval:刷新间隔时间,可以被设置为任意的正整数,单位毫秒。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size:内存资源数目,可以被设置为任意正整数。默认值是1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。
-->
<cache eviction="FIFO" size="2" readOnly="false" />
</mapper>
5.3 SQL语句级缓存配置
在相关的Mapper.xml文件中配置SQL查询,关键代码如下(示例):
<!-- useCache默认值为true,设为false时缓存不起作用 -->
<select id="selectOne" parameterType="int" resultMap="deptResultMap" useCache="true" >
select * from dept where dept_id=#{id}
</select>
6.XML 中的特殊字符处理
如果 MyBatis 使用 XML 配置,那不可避免地会遇到一些对 XML 来说是特殊的字符。如小于号 “<”,因此要进行转义。主要有两个方式:
6.1 使用转义实体
下面是五个在 XML 文档中预定义好的转义实体:
< < 小于号
> > 大于号
& &
' ' 单引号
" " 双引号
小于等于“<=”,其转义为:<=
大小等于“>=”,转义为:>=
6.2 使用 CDATA 部件
CDATA 部件以"<![CDATA[" 标记开始,以"]]>"标记结束。在"<![CDATA["和"]]>"之间 的特殊字符的意义都不起作用,而转变为普通字符串内容。
在 MyBatis 的 XML 映射语句配置文件中,如果 SQL 语句有特殊字符,使用CDTA 部件括起来,如:
<select id= "selectBlog_use_collection"
resultMap= "blogResult" >
<![CDATA[ SELECT id , title, author_id as authored FROM BLOG WHERE ID > 0 and ID < 10 ]]> </select>
7. Spring+myBatis整合
7.1 准备工作
新建项目并导入jar包
配置mybatis-config.xml
创建库及表
创建实体
编写映射文件,修改mybatis-config.xml内容
进行简单测试(除了导入spring相关jar包外,以上内容可能直接使用上一章节内容)
7.2配置applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 配置数据源,记得去掉myBatis-config.xml的数据源相关配置 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8" />
<property name="user" value="root" />
<property name="password" value="root" />
</bean>
<!-- 配置session工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:myBatis-config.xml" />
</bean>
<!-- 配置事务管理器,管理数据源事务处理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置SessionTemplate,以封装了繁琐的数据操作-->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
7.3修改myBatis-config.xml
去掉数据源配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="cn.itcast.entity.Dept" alias="Dept" />
</typeAliases>
<mappers>
<mapper resource="cn/itcast/entity/DeptMapper.xml" />
</mappers>
</configuration>
7.4编写dao层接口及实现
DeptDao.java
public interface DeptDao {
//根据部门ID查询部门信息
public Dept selectOne(int deptId);
}
修改接口实现类:DeptDaoImpl.java
public class DeptDaoImpl implements DeptDao{
private SqlSessionTemplate sqlSessionTemplate;
public SqlSessionTemplate getSqlSessionTemplate() {
return sqlSessionTemplate;
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
//根据部门ID查询部门信息
public Dept selectOne(int deptId){
System.out.println("dao :"+deptId);
//SqlSession session=null;
Dept dept=null;
try {
dept=sqlSessionTemplate.selectOne("cn.itcast.entity.DeptMapper.selectOne",deptId);
System.out.println("dao.dept:"+dept);
} catch (Exception e) {
e.printStackTrace();
}
return dept;
}
}
7.5编写业务层代码
业务层接口略,这里只写业务层实现类:DeptServiceImpl.java
public class DeptServiceImpl {
private DeptDao deptDao;
public Dept selectOne(int deptId){
Dept dept=deptDao.selectOne(deptId);
return dept;
}
public DeptDao getDeptDao() {
return deptDao;
}
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
}
7.6 配置bean信息到sping配置文件
<!-- DAO层部门信息表的数据操作对象 -->
<bean id="deptDao" class="cn.itcast.dao.impl.DeptDaoImpl" >
<property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
</bean>
<!-- 业务层部门信息业务处理对象 -->
<bean id="deptService" class="cn.itcast.service.impl.DeptServiceImpl">
<property name="deptDao" ref="deptDao"/>
</bean>
7.7编写测试类
@Test
public void selectOne() {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
DeptServiceImpl deptService=(DeptServiceImpl)context.getBean("deptService");
Dept dept = deptService.selectOne(1);
System.out.println("dept:" + dept);
}
7.8简化配置
7.8.1 扫描式加载SQL映射文件
修改myBatis-config.xml文件,去掉<mappers>配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="cn.itcast.entity.Dept" alias="Dept" />
</typeAliases>
<!-- 采用扫描式加载映射文件,以下将不用配置,可以减少映射文件过多时维护的麻烦 -->
<!-- <mappers>
<mapper resource="cn/itcast/entity/DeptMapper.xml" />
</mappers>
-->
</configuration>
修改applicationContext.xml,为SqlSessionFactoryBean设置mapperLocations属性
<!-- 配置session工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:myBatis-config.xml" />
<!-- 配置扫描式加载SQL映射文件 -->
<property name="mapperLocations" value="classpath:cn/itcast/entity/*.xml"/>
</bean>
7.8.2 MapperScannerConfigurer简化配置
1) 在spring配置文件中添加MapperScannerConfigurer 配置并去掉所有的Dao接口实现类配置
<!-- 配置 转换器,对于在basePackage设置的包(包括子包)下的接口类的全类名和在Mapper.xml文件中定义过的命名空间一致,
spring将会生成对应的代理对象(在调用 的地方通过@Autowired方式将可以注入接口实例)-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<property name="basePackage" value="cn.itcast.dao"/>
</bean>
<!-- DAO层部门信息表的数据操作对象,上面如果配置MapperScannerConfigurer转换器,DAO接口将不再使用实现类 -->
<!--
<bean id="deptDao" class="cn.itcast.dao.impl.DeptDaoImpl" >
<property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
</bean>
-->
<!-- 业务层部门信息业务处理对象 -->
<bean id="deptService" class="cn.itcast.service.impl.DeptServiceImpl">
<!-- 上面如果配置MapperScannerConfigurer转换器,DAO接口将不再使用实现类注入 -->
<!-- <property name="deptDao" ref="deptDao"/> -->
</bean>
2) 检查或修改DeptMapper.xml文件:
注意:命名空间+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">
<!-- 这时的命名空间就需要和dao接口类全类名一致了 -->
<mapper namespace="cn.itcast.dao.DeptDao">
<!-- 表字段和对应实体属性命名一致时可以不配置 -->
<resultMap id="deptResultMap" type="Dept">
<id property="deptId" column="dept_id" />
<result property="deptName" column="dept_name" />
<result property="deptAddress" column="dept_address" />
</resultMap>
<!-- 这时的id就需要和dao接口的方法一致了 -->
<select id="selectOne" parameterType="int" resultMap="deptResultMap">
select * from dept where dept_id=#{id}
</select>
</mapper>
3)业务类中,使用@Autowired为DAO接口注入对象
public class DeptServiceImpl {
@Autowired
private DeptDao deptDao;
//省略其它代码
4)删除Dao实现类(存在也没有意义)