目录
一、基础回顾
mybatis(一)
mybatis(二)
mybatis(三)
二、高级应用
2.1 二级缓存整合redis
2.1.1 使用的redis的 因果
- 为什么要整合 用redis 整合二级缓存?
如果 你是 单服务器工作,可以使用mybatis自带的二级缓存。
但是 现在大多数是 ,分布式的 服务。服务器之间不能 完成 二级缓存的通信。这时候就需要使用到redis 来为我们完成 分布式缓存。
举个栗子
- 假设现在有两个服务器1和2,用户访问的时候访问了 1服务器,查询后的缓 存就会放在1服务器上,假设现在有个用户访问的是2服务器,那么他在2服务器上就无法获取刚刚那个 缓存。
为了解决这个问题,就得找一个分布式的缓存,专门用来存储缓存数据的,这样不同的服务器要缓存数
据都往它那里存,取缓存数据也从它那里取。
如下图。
2.1.2 使用的redis的具体实现
- mybatis提供了一个eache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
- mybatis提供了一个针对cache接口的redis实现类,该类存在mybatis-redis。
实现:
- pom文件
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-redis</artifactId>
<version>1.0.0-beta2</version>
</dependency>
2.配置文件
<?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.lagou.mapper.IUserMapper">
<cache type="org.mybatis.caches.redis.RedisCache" />
<select id="findAll" resultType="com.lagou.pojo.User" useCache="true">
select * from user
</select>
3.redis.properties
redis.host=localhost
redis.port=6379
redis.connectionTimeout=5000
redis.password= redis.database=0
- 测试类
@Test
public void SecondLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
IUserMapper mapper1 = sqlSession1.getMapper(IUserMapper.class);
lUserMapper mapper2 = sqlSession2.getMapper(lUserMapper.class);
lUserMapper mapper3 = sqlSession3.getMapper(IUserMapper.class);
User user1 = mapper1.findUserById(1);
sqlSession1.close();
//清空一级缓存
User user = new User();
user.setId(1);
user.setUsername("lisi");
mapper3.updateUser(user);
sqlSession3.commit();
User user2 = mapper2.findUserById(1);
System.out.println(user1 == user2);
}
2.1.3 使用的redis的源码的说明
2.2 插件的使用
2.2.1 插件简介
一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展。这样的好处是显而易见
的,一是增加了框架的灵活性。二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工
作。以MyBatis为例,我们可基于MyBati s插件机制实现分页、分表,监控等功能。由于插件和业务 无
关,业务也无法感知插件的存在。因此可以无感植入插件,在无形中增强功能.
2.2.2 Mybatis插件简介
Mybati s作为一个应用广泛的优秀的ORM开源框架,这个框架具有强大的灵活性,在四大组件
(Executor、StatementHandler、ParameterHandler、ResultSetHandler)处提供了简单易用的插 件扩
展机制。Mybatis对持久层的操作就是借助于四大核心对象。MyBatis支持用插件对四大核心对象进 行
拦截,对mybatis来说插件就是拦截器,用来增强核心对象的功能,增强功能本质上是借助于底层的 动
态代理实现的,换句话说,MyBatis中的四大对象都是代理对象.
MyBatis所允许拦截的方法如下:
- 执行器Executor (update、query、commit、rollback等方法);
- SQL语法构建器StatementHandler (prepare、parameterize、batch、updates query等方 法);
- 参数处理器ParameterHandler (getParameterObject、setParameters方法);
- 结果集处理器ResultSetHandler (handleResultSets、handleOutputParameters等方法);
2.2.3 实现一个简单的自定义Mybatis插件
SqlMapConfig.xml
<plugins>
<plugin interceptor="com.lagou.plugin.MyPlugin">
<property name="name" value="Tom"/>
</plugin>
</plugins>
Usermapper.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="com.lagou.mapper.UserMapper">
<select id="selectUsers" resultType="com.lagou.pojo.User">
SELECT id,username FROM user
</select>
</mapper>
MyPlugin
package com.lagou.plugin;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.sql.Connection;
import java.util.Properties;
//拦截器的设置
@Intercepts({ //这里这个大括号,也就是说 这里可以定义对个@Signature 对 对个地方进行拦截,都用这个拦截器。
@Signature(type = StatementHandler.class, // 指定拦截的那个接口
method = "prepare", // 指定 要拦截的接口的 中要拦截的方法
args = {Connection.class, Integer.class}) // 指定 要拦截的接口的 中要拦截的方法 中的参数,按顺序,不要多,也不要少。如果方法重载,通过这个 来确定你要执行的方法。
})
public class MyPlugin implements Interceptor {
/**
* 拦截方法,只要别拦截的目标对象的目标方法别执行时,每次都会执行intercept方法
*
* @param invocation
* @return
* @throws Throwable
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("对方法进行了增强");
return invocation.proceed(); //执行原方法
}
/**
* 主要为了把当前的拦截器生成代理存到拦截器链中
*
* @param
* @return
*/
@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);
}
}
PluginTest
import com.lagou.mapper.UserMapper;
import com.lagou.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class PluginTest {
@Test
public void test() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = build.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.selectUsers();
users.forEach(System.out::println);
}
}
package com.lagou.pojo;
public class User {
private int id;
private String username;
public User(int id, String username) {
this.id = id;
this.username = username;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
'}';
}
}
UserMapper
package com.lagou.mapper;
import com.lagou.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectUsers();
}
2.2.4 pageHelper分页插件
MyBati s可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封
装,使用简单的方式即可获得分页的相关数据
开发步骤:
① 导入通用PageHelper的坐标
② 在mybatis核心配置文件中配置PageHelper插件
③ 测试分页数据获取
- 导入通用PageHelper坐标
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>
- 在mybatis核心配置文件中配置PageHelper插件\
<!--注意:分页助手的插件 配置在通用馆mapper之前*-->*
<plugin interceptor="com.github.pagehelper.PageHelper">
<!—指定方言 —>
<property name="dialect" value="mysql"/>
</plugin>
- 测试分页代码实现
@Test
public void testPageHelper() {
//设置分页参数
PageHelper.startPage(1, 2);
List<User> select = userMapper2.select(null);
for (User user : select) {
System.out.println(user);
}
}
}
获得分页相关的其他参数
//其他分页的数据
PageInfo<User> pageInfo = new PageInfo<User>(select);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo. getPages ());
System.out.println("当前页:"+pageInfo. getPageNum());
System.out.println("每页显万长度:"+pageInfo.getPageSize());
System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
- 开发步骤:
导入通用PageHelper的坐标
在mybatis核心配置文件中配置PageHelper插件
测试分页数据获取
2.2.5 通用 mapper
什么是通用Mapper
通用Mapper就是为了解决单表增删改查,基于Mybatis的插件机制。开发人员不需要编写SQL,不需要
在DAO中增加方法,只要写好实体类,就能支持相应的增删改查方法
如何使用
- 首先在maven项目,在pom.xml中引入mapper的依赖
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.1.2</version>
</dependency>
- Mybatis配置文件中完成配置
<plugins>
<!--分页插件:如果有分页插件,要排在通用mapper之前-->
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
</plugin>
<plugin interceptor="tk.mybatis.mapper.mapperhelper.MapperInterceptor"> <!-- 通用Mapper接口,多个通用接口用逗号隔开 -->
<property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
</plugin>
</plugins>
- 实体类设置主键
@Table(name = "t_user")
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
}
- 定义通用mapper
import com.lagou.domain.User;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<User> {
}
- 测试
public class UserTest {
@Test
public void test1() throws IOException {
Inputstream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setId(4);
//(1)mapper基础接口 //select 接口
User user1 = userMapper.selectOne(user);
//根据实体中的属性进行查询,只能有 — 个返回值
List<User> users = userMapper.select(null);
//查询全部结果
userMapper.selectByPrimaryKey(1);
//根据主键字段进行查询,方法参数必须包含完 整 的主键属性,查询条件使用等号
userMapper.selectCount(user);
//根据实体中的属性查询总数,查询条件使用等号
// insert 接口
int insert = userMapper.insert(user);
//保存一个实体,null值也会保存,不会使 用数据库默认值
int i = userMapper.insertSelective(user);
//保存实体,null的属性不会保存, 会 使用数据库默认值
// update 接口
int i1 = userMapper.updateByPrimaryKey(user);
//根据主键更新实体全部字段, null值会被更新
// delete 接口
int delete = userMapper.delete(user);
//根据实体属性作为条件进行删除,查询条件 使用等号
userMapper.deleteByPrimaryKey(1);
//根据主键字段进行删除,方法参数必须包含完 整 的主键属性
// (2)example方法
Example example = new Example(User.class);
example.createCriteria().andEqualTo("id", 1);
example.createCriteria().andLike("val", "1");
//自定义查询
List<User> users1 = userMapper.selectByExample(example);
}
}