src/main/resources/mybatis-config.xml:
<configuration>
<properties resource="jdbc.properties">properties>
<settings>
<setting name="logImpl" value="LOG4J" />
settings>
<typeAliases>
<package name="tk.mybatis.simple.model"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
transactionManager>
<dataSource type="UNPOOLED">
<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="tk/mybatis/simple/mapper/CountryMapper.xml"/>
mappers>
configuration>
insert 返回主键
<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
insert into sys_user(
user_name, user_password)
values(
#{userName}, #{userPassword})
insert>
<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
insert into sys_user(
user_name, user_password)
values(
#{userName}, #{userPassword})
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
SELECT LAST_INSERT_ID()
selectKey>
insert>
Oracle:
<selectKey keyColumn="id" result="long" keyProperty="id" order="BEFORE">
SELECT SEQ_ID.nextval from dual
selectKey>
<select id="selectAll" resultType="tk.mybatis.simple.model.SysUser">
select id,
user_name userName,
user_password userPassword
from sys_user
select>
使用 resultType 需要设置别名来实现自动映射
@Select({"select id, role_name roleName ",
"from sys_role ",
"where id = #{id}"})
SysRole selectById(Long id);
@Select({"select id, role_name roleName
from sys_role
where id = #{id}"})
SysRole selectById(Long id);
// 定义 id,实现共用
@Results(id = "roleResultMap", value = {
@Result(property = "id", column = "id", id = true),
@Result(property = "roleName", column = "role_name")
})
@Results({
@Result(property = "id", column = "id", id = true),
@Result(property = "roleName", column = "role_name")
})
@Select("select id, role_name from sys_role where id = #{id}")
SysRole selectById2(Long id);
@ResultMap("roleResultMap")
@Select("select * from sys_role")
List<SysRole> selectAll();
@Insert({"insert into sys_role(role_name)",
"values(#{roleName})"})
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert2(SysRole sysRole);
@Insert({"insert into sys_role(role_name)",
"values(#{roleName})"})
@SelectKey(statement = "SELECT LAST_INSERT_ID()",
keyProperty = "id",
resultType = Long.class,
before = false)
int insert3(SysRole sysRole);
@SelectProvider(type = PrivilegeProvider.class, metod = "selectById")
SysPrivilege selectById(Long id);
PrivilegeProvider:
public class PrivilegeProvider {
// 直接返回字符串 sql 也行
public String selectById(final Long id) {
result new SQL() {
{
SELECT("id, privilege_name, privilege_url");
FROM("sys_privilege");
WHERE("id = #{id}");
}
}.toString();
}
}
<if test="userName != null and userName != ''">
and user_name like concat('%', #{userName}, '%')
if>
<choose>
<when test="userName != null">
...
when>
<otherwhise>otherwhise>
choose>
<where>
<if test="userName != null and userName != ''">
and user_name like concat('%', #{userName}, '%')
if>
where>
<update id="updateByIdSelective">
update sys_user
<set>
<if test="userName != null and userName != ''">
user_name = #{userName},
if>
<if test="userPassword != null and userPassword != ''">
user_password = #{userPassword},
if>
set>
where id = #{id}
update>
where 标签对应 trim 的实现:
<trim prefix="WHERE" prefixOverrides="AND |OR">
...
trim>
set 标签对应的 trim 实现:
<trim prefix="SET" suffixOverrides=",">
...
trim>
where id in
<foreach collection="list" open="(" separator="," close=")" item="id" index="i">
#{id}
foreach>
<if test="userName != null and userName != ''">
<bind name="userNameLike" value="'%' + userName + '%'"/>
and user_name like #{userNameLike}
if>
<select id="selectUserAndRoleById" resultType="tk.mybatis.simple.model.SysUser">
select u.id, u.user_name userName, u.user_password userPassword,
r.id "role.id", r.role_name "role.roleName"
from sys_user u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on ur.role_id = r.id
where u.id = #{id}
select>
<resultMap id="userRoleMap" type="tk.mybatis.simple.model.SysUser">
<result property="id" column="id"/>
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<result property="role.id" column="role_id"/>
<result property="role.roleName" column="role_name"/>
resultMap>
<resultMap id="userRoleMap" type="tk.mybatis.simple.model.SysUser">
<association property="role" columnPrefix="role_" javaType="tk.mybatis.simple.model.SysRole">
<result property="id" column="id"/>
<result property="roleName" column="role_name"/>
association>
resultMap>
<resultMap id="userRoleListMap" extends="userMap" type="tk.mybatis.simple.model.SysUser">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<collection property="roleList" columnPrefix="role_" javaType="tk.mybatis.simple.model.SysRole">
<id property="id" column="id"/>
<result property="roleName" column="role_name"/>
collection>
resultMap>
类似于 switch
<resultMap id="rolePrivilegeListMapChoose" type="tk.mybatis.simple.model.SysRole">
<discriminator column="enabled" javaType="int">
<case value="1" resultMap="rolePrivilegeListMapSelect"/>
<case value="0" resultMap="roleMap"/>
discriminator>
resultMap>
在 mybatis-config.xml 中添加配置:使用枚举的索引进行处理
<typeHandlers>
<typeHandler javaType="tk.mybatis.simple.type.Enabled"
handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
typeHandlers>
public class EnabledTypeHandler implements TypeHanlder<Enabled> {
private final Map<Integer, Enabled> enabledMap = new HashMap<Integer, Enabled>();
public EnabledTypeHandler() {
for (Enabled enabled : Enabled.values()) {
enabledMap.put(enabled.getValue(), enabled);
}
}
@Override
public void setParameter(PreparedStatement ps, int i,
Enabled parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter.getValue());
}
@Override
public Enabled getResult(ResultSet rs, int columnIndex) throws SQLException {
Integer value = rs.getInt(columnIndex);
return enabledMap.get(value);
}
@Override
public Enabled getResult(CallableStatement cs, int columnIndex) throws SQLException {
Integer value = cs.getInt(columnIndex);
return enabledMap.get(value);
}
}
在 mybatis-config.xml 中配置:
<typeHandlers>
<typeHandler javaType="tk.mybatis.simple.type.Enabled"
handler="tk.mybatis.simple.type.EnabledTypeHandler"/>
typeHandlers>
范围: SqlSession
概述:
MyBatis 的一级缓存存在于 SqlSession 的生命周期中,默认开启
在同一个 SqlSession 中查询时,MyBatis 会把执行的方法和参数通过算法生成缓存的键值,将键值和查询结果存入一个 Map 对象中
清空缓存: 更新或删除操作会清空缓存,或使用 SqlSession#clearCache() 方法进行手动刷新
flushCache=“true”: 查询数据前清空当前的一级缓存
<select id="selectById" flushCache="true" resultMap="userMap">
select * from sys_user where id = #{id}
select>
范围: Mapper(namespace)
概述:
默认不开启
会重新创建一个对象进行 copy
无法实现分布式缓存
二级缓存全局开关: 不必配置,默认已为 true
mybatis-config.xml:
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
开启二级缓存:
<mapper namespace="tk.mybatis.simple.mapper.RoleMapper">
<cache/>
mapper>
默认的二级缓存会有如下效果
cache 可配置的属性:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
当只使用注解方式配置二级缓存时:
@CacheNamespace
public interface RoleMapper {
...
}
配置属性:
@CacheNamespace(
eviction = FifoCache.class,
flushInterval = 60000,
size = 512,
readWrite = true
)
当同时使用注解方式和 XML 映射文件时: 使用参照缓存
这样就会使用命名空间为 tk.mybatis.simple.mapperRoleMapper 的缓存配置,即 RoleMapper.xml 中配置的缓存
引用 Mapp 接口中配置的二级缓存
<cache-ref namespace="tk.mybatis.simple.mapper.RoleMapper"/>
使用可读写缓存,通过序列化和反序列化来保证通过缓存获取数据时,得到的是一个 新的实例。
sqlSession = getSqlSession();
try {
// 获取 RoleMapper 接口
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
// 调用 selectById 方法,查询 id = 1 的用户
SysRole role2 = roleMapper.selectById(1L);
// 第二个 session 获取的用户名是 New Nam
Assert.assertEquals("New Name", role2.getRoleName());
// 这里的 role2 和前一个 session 查询的结果是两个不同的实例
Assert.assertNotEquals(role1, role2);
// 获取 role3
SysRole role3 = roleMapper.selectById(1L);
// 这里的 role2 和 role3 是两个不同的实例
Assert.assertNotEquals(role2, role3);
} finally {
// 关闭 sqlSession
sqlSession.close();
}
加入依赖
<dependency>
<groupId>org.mybatis.cachesgroupId>
<artifactId>mybatis-redisartifactId>
<version>1.0.0-beta2version>
dependency>
使用缓存
@CacheNamespace(implementation = RedisCache.class)
public interface IUserMapper {
...
}
对 mybatis 的扩展,其原理是拦截器,在四大组件(Executor
、StatementHandler
、ParamterHandler
、ResultSetHandler
)使用时拦截处理
允许拦截的方法:
原理:
在四大组件对象创建时遍历所有的拦截器,每个拦截器都使用 interceptor.plugin(target) 方法对目标类进行增强
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object object, BoundSql sql, InterceptorChain interceptorChain) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,object,sql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
@Intercepts({
@Signature(
// 指定组件
type = Executor.class,
// 指定方法
method = "query",
// 指定参数确定方法
args = {MapperStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)
})
public class ExamplePlugin implements Interceptor {
// 每次操作都会进入该方法
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("对方法进行了增强....");
return invocation.proceed();
}
// 把这个拦截器生成一个代理放到拦截器链中
@Override
public Object plugin(Object target) {
System.out.println("将要包装的目标对象" + target);
return Plugin.wrap(target, this);
}
// 插件初始化时调用一次,获取配置的属性,如下:
@Override
public void setProperties(Properties properties) {
System.out.println("初始化参数" + properties);
}
}
<plugins>
<plugin interceptor="com.xxx.plugin.ExamplePlugin">
<property name="name" value="Bob"/>
plugin>
plugins>