JDBC
Hibernate 和 JPA
MyBatis是一个半自动化的持久化层框架
CREATE TABLE employee(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
last_name VARCHAR(255),
gender CHAR(1),
email VARCHAR(255)
);
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>6.0.6version>
dependency>
public class Employee{
private Integer id;
private String lastName;
private String email;
private String gender;
......
}
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
dataSource>
environment>
environments>
<mappers>
<mapper resource="mapper/EmployeeMapper.xml" />
mappers>
configuration>
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="abc">
<select id="getEmpById" resultType="com.example.mybatis.pojo.Employee">
select id,last_name lastName,email,gender from employee where id = #{id}
select>
mapper>
/**
* 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 有数据源一些运行环境信息
* 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。
* 3、将sql映射文件注册在全局配置文件中
* 4、写代码:
* 1)、根据全局配置文件得到SqlSessionFactory;
* 2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查一个sqlSession就是代表和数据库的一次会话,用完关闭
* 3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。
*
* @throws IOException
*/
@Test
public void test() throws IOException {
// 2、获取sqlSession实例,能直接执行已经映射的sql语句
// sql的唯一标识:statement Unique identifier matching the statement to use.
// 执行sql要用的参数:parameter A parameter object to pass to the statement.
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try {
Employee employee = openSession.selectOne(
"abc.getEmpById", 1);
System.out.println(employee);
} finally {
openSession.close();
}
}
MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置(settings)和属性(properties)信息。文档的顶层结构如下:
<configuration>
<properties resource="application.properties"/>
configuration>
application.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
jdbc.username=root
jdbc.password=123456
如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:
这是 MyBatis 中极为重要的调整设置,它们会改变MyBatis 的运行时行为。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="cacheEnabled" value="true"/>
settings>
设置参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 该配置影响的所有映射器中配置的缓存的全局开关。 | true/false | TRUE |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时。所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。 | true/false | FALSE |
useColumnLabel | 使用列标签代替列名。不同的驱动在这方面会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。 | true/false | TRUE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数。 | Any positive integer | Not Set (null) |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则( camel case )映射即从经典数据库列名A_ COLUMN到经典Java属性名aColumn的类似映射 | true/false | FALSE |
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
<configuration>
...
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
typeAliases>
configuration>
当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<configuration>
...
<typeAliases>
<package name="domain.blog"/>
typeAliases>
configuration>
每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
值得注意的是, MyBatis已经为许多常见的 Java 类型内建了相应的类型别名。它们都是大小写不敏感的,我们在起别名的时候千万不要占用已有的别名。
无论是 MyBatis 在预处理语句( PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
类型处理器 | Java 类型 | JDBC 类型 |
---|---|---|
BooleanTypeHandler | java.lang.Boolean, boolean | 数据库兼容的 BOOLEAN |
ByteTypeHandler | java.lang.Byte, byte | 数据库兼容的 NUMERIC 或 BYTE |
ShortTypeHandler | java.lang.Short, short | 数据库兼容的 NUMERIC 或 SHORT INTEGER |
IntegerTypeHandler | java.lang.Integer, int | 数据库兼容的 NUMERIC 或 INTEGER |
LongTypeHandler | java.lang.Long, long | 数据库兼容的 NUMERIC 或 LONG INTEGER |
FloatTypeHandler | java.lang.Float, float | 数据库兼容的 NUMERIC 或 FLOAT |
DoubleTypeHandler | java.lang.Double, double | 数据库兼容的 NUMERIC 或 DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | 数据库兼容的 NUMERIC 或 DECIMAL |
StringTypeHandler | java.lang.String | CHAR, VARCHAR |
日期类型的处理
日期和时间的处理, JDK1.8以前一直是个头疼的问题。我们通常使用JSR310规范领导者Stephen Colebourne创建的Joda-Time来操作。 1.8已经实现全部的JSR310规范了。日期时间处理上,我们可以使用MyBatis基于JSR310( Date and Time API)编写的各种日期时间类型处理器。MyBatis3.4以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.InstantTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalDateTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalDateTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalTime TypeHandler" />
<typeHandler handler="org.apache.ibatis.type.0ffsetDateTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.OffsetTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.ZonedDateTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.YearTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.MonthTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.YearMonthTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.JapaneseDateTypeHandler" />
typeHandlers>
自定义类型处理器步骤:
org.apache.ibatis.type.TypeHandler
接口或者继承org.apache.ibatis.type.BaseTypeHandler
插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。 插件通过动态代理机制,可以介入四大对象的任何一个方法的执行。
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。每种环境使用一个environment标签进行配置并指定唯一标识符。可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境。
environment-指定具体环境
transactionManager
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
dataSource>
environment>
<environment id="prod">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
dataSource>
environment>
environments>
MyBatis 可以根据不同的数据库厂商执行不同的语句。
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
<property name="MySQL" value="mysql" />
databaseIdProvider>
<mappers>
<mapper resource="mapper/EmployeeMapper.xml" />
<mapper resource="mapper/EmployeeMapper2.xml" />
<mapper resource="mapper/DepartmentMapper.xml" />
<mapper resource="mapper/DynamicSQLMapper.xml" />
mappers>
mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys()
:
<insert id="addEmp" parameterType="com.example.mybatis.pojo.Employee"
useGeneratedKeys="true" keyProperty="id" >
insert into employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
insert>
mybatis不会做特殊处理,#{参数名/任意名}
:取出参数值。
mybatis会做特殊处理。通常操作:
public Employee getEmpByIdAndLastName(Integer id,String lastName)
;#{id}
,#{lastName}
上述操作会抛出异常:org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [1, 0, param1, param2]
解决方法:
<select id="getEmpByIdAndLastName" resultType="com.example.mybatis.pojo.Employee">
select * from employee where id = #{id} and last_name=#{lastName}
select>
<select id="getEmpByIdAndLastName2" resultType="com.example.mybatis.pojo.Employee">
select * from employee where id = #{0} and last_name=#{1}
select>
<select id="getEmpByIdAndLastName3" resultType="com.example.mybatis.pojo.Employee">
select * from employee where id = #{param1} and last_name=#{param2}
select>
<select id="getEmpByIdAndLastName4" resultType="com.example.mybatis.pojo.Employee">
select * from employee where id = #{id} and last_name=#{lastName}
select>
public Employee getEmpByIdAndLastName(Integer id, String name);
public Employee getEmpByIdAndLastName2(Integer id, String name);
public Employee getEmpByIdAndLastName3(Integer id, String name);
public Employee getEmpByIdAndLastName4(@Param("id")Integer id, @Param("lastName")String name);
POJO:如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;
#{属性名}
:取出传入的pojo的属性值Map:如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map
#{key}
:取出map中对应的值
<select id="getEmpByMap" resultType="com.example.mybatis.pojo.Employee">
select * from employee where id = #{id} and last_name=#{lastName}
select>
public Employee getEmpByMap(Map<String, Object> map);
TO:如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象,如:
Page{
int index;
int size;
}
<select id="getEmpsByLastNameLike" resultType="com.example.mybatis.pojo.Employee">
select * from employee where last_name like #{lastName}
select>
public List<Employee> getEmpsByLastNameLike(String str);
<select id="getEmpByLastNameLikeReturnMap" resultType="com.example.mybatis.pojo.Employee">
select * from employee where last_name like #{lastName}
select>
<select id="getEmpByIdReturnMap" resultType="map">
select * from employee where id=#{id}
select>
//多条记录封装一个map:Map:键是这条记录的主键,值是记录封装后的javaBean
//@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key
@MapKey("lastName")
public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);
//返回一条记录的map;key就是列名,值就是对应的值
public Map<String, Object> getEmpByIdReturnMap(Integer id);
<resultMap type="com.example.mybatis.pojo.Employee" id="MySimpleEmp">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
resultMap>
<select id="getEmpByIdWithResultMap" resultMap="MySimpleEmp">
select * from employee where id=#{id}
select>
//自定义结果映射规则
public Employee getEmpByIdWithResultMap(Integer id);
sql
CREATE TABLE employee(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
last_name VARCHAR(255),
gender CHAR(1),
email VARCHAR(255)
);
INSERT INTO employee (id, last_name, gender, email) VALUES(0,'shiftycat', 0, 'shiftycat.163.com');
INSERT INTO employee (id, last_name, gender, email) VALUES(2,'shiftlesscat', 1, 'shiftlesscat.163.com');
CREATE TABLE department(
id int(11) primary key auto_increment,
department_name varchar(255)
);
ALTER TABLE employee ADD COLUMN department_id int(11);
ALTER TABLE employee ADD CONSTRAINT fk_employee_department
FOREIGN KEY(department_id) REFERENCES department(id);
INSERT INTO department(department_name) values ('开发部');
INSERT INTO department(department_name) values ('测试部');
Employee类和Department类
public class Employee implements Serializable {
private Integer id;
private String lastName;
private String email;
private String gender;
private Department department;
......
}
public class Department {
private Integer id;
private String departmentName;
private List<Employee> emps;
......
}
<resultMap type="com.example.mybatis.pojo.Employee" id="MyDifEmp">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="gender" property="gender"/>
<result column="department_id" property="department.id"/>
<result column="department_name" property="department.departmentName"/>
resultMap>
<select id="getEmpAndDept" resultMap="MyDifEmp">
SELECT
e.id id,e.last_name last_name,e.gender gender,
e.department_id department_id, d.department_name department_name
FROM employee e, department d
WHERE e.department_id=d.id AND e.id=#{id}
select>
public Employee getEmpAndDept(Integer id);
<resultMap type="com.example.mybatis.pojo.Employee" id="MyDifEmp2">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="gender" property="gender"/>
<association property="department" javaType="com.example.mybatis.pojo.Department">
<id column="department_id" property="id"/>
<result column="department_name" property="departmentName"/>
association>
resultMap>
<select id="getEmpAndDept2" resultMap="MyDifEmp2">
SELECT
e.id id,e.last_name last_name,e.gender gender,
e.department_id department_id, d.department_name department_name
FROM employee e, department d
WHERE e.department_id=d.id AND e.id=#{id}
select>
public Employee getEmpAndDept2(Integer id);
DepartmentMapper.xml
<select id="getDeptById" resultType="com.example.mybatis.pojo.Department">
select id,department_name departmentName from department where id=#{id}
select>
EmployeeMapper
<resultMap type="com.example.mybatis.pojo.Employee" id="MyEmpByStep">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<association property="department"
select="com.example.mybatis.mapper.DepartmentMapper.getDeptById"
column="department_id">
association>
resultMap>
<select id="getEmpByIdStep" resultMap="MyEmpByStep">
select * from employee where id=#{id}
select>
我们每次查询Employee对象的时候,都将一起查询出来。部门信息在我们使用的时候再去查询。在全局配置文件中配置,实现懒加载
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
<resultMap type="com.example.mybatis.pojo.Department" id="MyDept">
<id column="did" property="id"/>
<result column="department_name" property="departmentName"/>
<collection property="emps" ofType="com.example.mybatis.pojo.Employee">
<id column="eid" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
collection>
resultMap>
<select id="getDeptByIdPlus" resultMap="MyDept">
SELECT d.id did,d.department_name department_name,
e.id eid,e.last_name last_name,
e.email email,e.gender gender
FROM department d LEFT JOIN employee e ON d.id=e.department_id
WHERE d.id=#{id}
select>
DepartmentMapper.xml
<resultMap type="com.example.mybatis.pojo.Department" id="MyDeptStep">
<id column="id" property="id"/>
<id column="department_name" property="departmentName"/>
<collection property="emps"
select="com.example.mybatis.mapper.EmployeeMapper.getEmpsByDeptId"
column="id">collection>
resultMap>
<select id="getDeptByIdStep" resultMap="MyDeptStep">
select id,department_name from department where id=#{id}
select>
EmployeeMapper
<select id="getEmpsByDeptId" resultType="com.example.mybatis.pojo.Employee">
select * from employee where department_id=#{deptId}
select>
在全局配置文件中配置,实现懒加载。
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
需要将多列的值传递过去,则将多列的值封装map传递:column="{key1=column1,key2=column2}"
fetchType=lazy
:表示使用延迟加载;
lazy
:延迟eager
:立即<resultMap type="com.example.mybatis.pojo.Department" id="MyDeptStep">
<id column="id" property="id"/>
<id column="department_name" property="departmentName"/>
<collection property="emps"
select="com.example.mybatis.mapper.EmployeeMapper.getEmpsByDeptId"
column="{deptId=id}" fetchType="lazy">collection>
resultMap>
<select id="getDeptByIdStep" resultMap="MyDeptStep">
select id,department_name from department where id=#{id}
select>
<resultMap type="com.example.mybatis.pojo.Employee" id="MyEmpDis">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<discriminator javaType="string" column="gender">
<case value="0" resultType="com.example.mybatis.pojo.Employee">
<association property="department"
select="com.example.mybatis.mapper.DepartmentMapper.getDeptById"
column="department_id" fetchType="eager" >
association>
case>
<case value="1" resultType="com.example.mybatis.pojo.Employee">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="last_name" property="email"/>
<result column="gender" property="gender"/>
case>
discriminator>
resultMap>
<select id="getEmpsWithDiscriminator" resultMap="MyEmpDis">
select * from employee limit 10
select>
<select id="getEmpsByConditionIf" resultType="com.example.mybatis.pojo.Employee">
select * from employee where
<if test="id!=null">
id=#{id}
if>
<if test="lastName!=null && lastName!=""">
and last_name like #{lastName}
if>
<if test="email!=null and email.trim()!=""">
and email=#{email}
if>
<if test="gender==0 or gender==1">
and gender=#{gender}
if>
select>
mybatis使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql,多出来的and或者or去掉(where只会去掉第一个多出来的and或者or,但最后一个多出来的and或者or则不会去掉)。
<select id="getEmpsByConditionIfWithWhere" resultType="com.example.mybatis.pojo.Employee">
select * from employee
<where>
<if test="id!=null">
id=#{id}
if>
<if test="lastName!=null && lastName!=""">
and last_name like #{lastName}
if>
<if test="email!=null and email.trim()!=""">
and email=#{email}
if>
<if test="gender==0 or gender==1">
and gender=#{gender}
if>
where>
select>
后面多出的and或者or where标签不能解决时:
prefix=""
:给拼串后的整个字符串加一个前缀;prefixOverrides=""
:前缀覆盖: 去掉整个字符串前面多余的字符;suffix=""
:给拼串后的整个字符串加一个后缀;suffixOverrides=""
:后缀覆盖:去掉整个字符串后面多余的字符。
<select id="getEmpsByConditionTrim" resultType="com.example.mybatis.pojo.Employee">
select * from employee
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
if>
<if test="lastName!=null && lastName!=""">
last_name like #{lastName} and
if>
<if test="email!=null and email.trim()!=""">
email=#{email} and
if>
<if test="gender==0 or gender==1">
gender=#{gender}
if>
trim>
select>
<select id="getEmpsByConditionChoose" resultType="com.example.mybatis.pojo.Employee">
select * from employee
<where>
<choose>
<when test="id!=null">
id=#{id}
when>
<when test="lastName!=null">
last_name like #{lastName}
when>
<when test="email!=null">
email = #{email}
when>
<otherwise>
gender = 0
otherwise>
choose>
where>
select>
<update id="updateEmp">
update employee
<set>
<if test="lastName!=null">
last_name=#{lastName},
if>
<if test="email!=null">
email=#{email},
if>
<if test="gender!=null">
gender=#{gender}
if>
set>
where id=#{id}
update>
collection
:指定要遍历的集合:
item
:将当前遍历出的元素赋值给指定的变量separator
:每个元素之间的分隔符open
:遍历出所有结果拼接一个开始的字符close
:遍历出所有结果拼接一个结束的字符index
:索引。遍历list的时候是index就是索引,item就是当前值
#{变量名}
:就能取出变量的值也就是当前遍历出的元素
<select id="getEmpsByConditionForeach" resultType="com.example.mybatis.pojo.Employee">
select * from employee
<foreach collection="ids" item="item_id" separator=","
open="where id in(" close=")">
#{item_id}
foreach>
select>
<insert id="addEmps">
insert into employee(last_name,email,gender,department_id)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
foreach>
insert>
<insert id="addEmps2">
<foreach collection="emps" item="emp" separator=";">
insert into employee(last_name,email,gender,department_id) values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
foreach>
insert>
mybatis默认还有两个内置参数:
_parameter
:代表整个参数
_databaseId
:如果配置了databaseIdProvider标签。
<bind name="lastName" value="'%'+lastName+'%'"/>
抽取可重用的sql片段。方便后面引用:
#{}
,而使用${}
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password sql>
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/>include>,
<include refid="userColumns"><property name="alias" value="t2"/>include>
from some_table t1
cross join some_table t2
select>
<sql id="insertColumn">
<if test="_databaseId=='oracle'">
employee_id,last_name,email
if>
<if test="_databaseId=='mysql'">
last_name,email,gender,d_id
if>
sql>
<insert id="addEmps">
insert into tbl_employee(
<include refid="insertColumn">include>
)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
foreach>
insert>
MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。MyBatis系统中默认定义了两级缓存,一级缓存和二级缓存。
一级缓存(local cache),即本地缓存,作用域默认为sqlSession。当 Session flush 或 close 后, 该Session 中的所有 Cache 将被清空。本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域。在mybatis3.1之后, 可以配置本地缓存的作用域. 在 mybatis.xml 中配置。
一级缓存失效的四种情况
二级缓存(second level cache),全局作用域缓存。二级缓存默认不开启,需要手动配置。MyBatis提供二级缓存的接口以及实现,缓存实现要求 POJO实现Serializable接口。二级缓存在 SqlSession 关闭或提交之后才会生效。
cache标签的属性:
eviction:缓存的回收策略:
LRU
– 最近最少使用的:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:移除基于垃圾回收器状态和软引用规则的对象。WEAK
– 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。默认的是 LRU。
flushInterval:缓存刷新间隔
readOnly:是否只读:
size:缓存存放多少元素;
type=“”:指定自定义缓存的全类名;
使用步骤:
全局配置文件中开启二级缓存:
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
需要使用二级缓存的映射文件处使用cache配置缓存:
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024">cache>
Pojo类实现序列化
public class Employee implements Serializable {
private static final long serialVersionUID = -7390587151857533202L;
private Integer id;
private String lastName;
private String email;
private String gender;
......
}
flushCache=false
。EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。MyBatis定义了Cache接口方便我们进行自定义扩展。
package com.example.mybatis.pojo;
import java.util.concurrent.locks.ReadWriteLock;
public interface Cache {
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
ReadWriteLock getReadWriteLock();
}
步骤:
添加依赖:mybatis-ehcache
<dependency>
<groupId>org.mybatis.cachesgroupId>
<artifactId>mybatis-ehcacheartifactId>
<version>1.2.1version>
dependency>
编写ehcache.xml
配置文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="./ehcache" />
<defaultCache
maxElementsInMemory="10000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
defaultCache>
ehcache>
DepartmentMapper.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis.mapper.DepartmentMapper">
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
此外:
若想在命名空间中共享相同的缓存配置和实例,可以使用 cache-ref 元素来引用另外一个缓存。
<mapper namespace="com.example.mybatis.dao.DepartmentMapper">
<cache-ref namespace="com.example.mybatis.dao.EmployeeMapper"/>
巨輪-MyBatis学习笔记:https://blog.csdn.net/u011863024/article/details/107854866