1.插件原理
在四大对象创建的时候
1.每个创建出来的对象不是直接返回的,而是调用interceptorChain.pluginAll(statementHandler);
2.获得所有的Inteceptor(拦截器)(插件需要实现的接口)
3.插件机制,我们可以使用插件为目标对象创建一个代理对象: AOP(面向切面的编程方式)
我们的插件可以为四大对象创建出代理对象;
代理对象就可以拦截到四大对象的每一个执行;
调用interceptor.plugin(target);返回target包装后的对象
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
2.实现一个插件类
1.编写一个Interceptor的实现类
2.使用@Intercepts注解完成插件签名
/*插件:告诉MyBatis当前插件用来拦截哪个对象的哪个方法*/
@Intercepts({@Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)})
public class MyFirstPlugin implements Interceptor{
/*
* intercept:拦截
* 拦截目标方法的目标方法的执行
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
// TODO Auto-generated method stub
System.out.println("MyFirstPlugin+intercept:"+invocation.getMethod());
//执行目标方法
Object proceed=invocation.proceed();
//返回执行后的返回值
return proceed;
}
/* plugin:
* 包装目标对象:包装:为目标对象创建一个代理对象
*/
@Override
public Object plugin(Object target) {
System.out.println("MyFirstPlugin+plugin:"+target);
// 可以借助Plugin的wrap方法来使用当前Interceptor包装我们目标对象
Object wrap=Plugin.wrap(target, this);
//返回为当前target创建的动态代理
return wrap;
}
/* 将插入注册时的property属性设置进来
*
* */
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
System.out.println("插件配置的信息:"+properties);
}
}
3.将写好的插件注册到全局配置文件中
<plugins>
<plugin interceptor="com.atguigu.mybatis.dao.MyFirstPlugin">
<property name="username" value="root"/>
<property name="password" value="123456"/>
</plugin>
</plugins>
测试运行结果如下:
插件配置的信息:{password=123456, username=root}
MyFirstPlugin+plugin:org.apache.ibatis.executor.CachingExecutor@4d18aa28
MyFirstPlugin+plugin:org.apache.ibatis.scripting.defaults.DefaultParameterHandler@18230356
MyFirstPlugin+plugin:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@60d1a32f
MyFirstPlugin+plugin:org.apache.ibatis.executor.statement.RoutingStatementHandler@531c311e
DEBUG 07-13 22:11:04,342 ==> Preparing: select * from tb1_employee where id = ? (BaseJdbcLogger.java:145)
MyFirstPlugin+intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
DEBUG 07-13 22:11:04,393 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145)
DEBUG 07-13 22:11:04,483 <== Total: 1 (BaseJdbcLogger.java:145)
Employee [id=1, lastName=jerry, email=jerry@atguigu.com, gender=0]
3.多个插件运行流程
多个插件就会产生多层代理
创建动态代理的时候,是按照插件配置顺序创建层层代理对象。执行目标方法之后,按照逆向顺序执行。
4.分页插件的配置和使用
1.导入jar包
图片29
2.修改配置文件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3.测试代码如下:
@Test
public void test01() throws Exception{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession=sqlSessionFactory.openSession();
//EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);//代理类
//Employee employee=mapper.getEmpById(1);
//System.out.println(employee);
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
Page page=PageHelper.startPage(1,5);
List<Employee> emps=mapper.getEmps();
//PageInfo<Employee> info=new PageInfo<>(emps);
PageInfo<Employee> info=new PageInfo<>(emps,5);
for(Employee employee:emps) {
System.out.println(employee);
}
/*
* System.out.println("当前分页:"+page.getPageNum());
* System.out.println("总记录数:"+page.getTotal());
* System.out.println("每页的记录数:"+page.getPageSize());
* System.out.println("总页数:"+page.getPages());
*/
System.out.println("当前分页:"+info.getPageNum());
System.out.println("总记录数:"+info.getTotal());
System.out.println("每页的记录数:"+info.getPageSize());
System.out.println("总页数:"+info.getPages());
System.out.println("是否第一页:"+info.isIsFirstPage());
System.out.println("连续显示的页码:");
int[] nums=info.getNavigatepageNums();
for(int i=0;i<nums.length;i++) {
System.out.println(nums[i]);
}
}
4.运行结果
DEBUG 07-15 10:59:12,504 ==> Preparing: SELECT count(0) FROM tb1_employee (BaseJdbcLogger.java:145)
DEBUG 07-15 10:59:12,542 ==> Parameters: (BaseJdbcLogger.java:145)
DEBUG 07-15 10:59:12,580 <== Total: 1 (BaseJdbcLogger.java:145)
DEBUG 07-15 10:59:12,582 ==> Preparing: select * from tb1_employee LIMIT 5 (BaseJdbcLogger.java:145)
DEBUG 07-15 10:59:12,584 ==> Parameters: (BaseJdbcLogger.java:145)
DEBUG 07-15 10:59:12,589 <== Total: 5 (BaseJdbcLogger.java:145)
Employee [id=1, lastName=jerry, email=jerry@atguigu.com, gender=0]
Employee [id=3, lastName=%e%, email=test1, gender=0]
Employee [id=8, lastName=smith, email=smith, gender=1]
Employee [id=9, lastName=smith2, email=smith, gender=1]
Employee [id=10, lastName=smith3, email=smith, gender=0]
当前分页:1
总记录数:18
每页的记录数:5
总页数:4
是否第一页:true
连续显示的页码:
1
2
3
4
5.设置批量处理
sql配置文件代码如下
<insert id="addEmp">
insert into tb1_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
</insert>
测试代码如下
@Test
public void test02() throws Exception{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession=sqlSessionFactory.openSession(ExecutorType.BATCH);
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
for(int i=0;i<10000;i++) {
mapper.addEmp(new Employee("name"+i,"email"+i,"0"));
}
openSession.commit();
openSession.close();
}
批量处理的过程:
预编译sql一次==》设置参数==》10000次==》执行1次
6.SSM中配置批量处理
配置文件如下
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- spring事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置批量 -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="dataSourceTransactionManager"></constructor-arg>
<constructor-arg name="executorType" ref="BATCH"></constructor-arg>
</bean>
使用方法如下:
@Service
public class EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Autowired
private List<Employee> sqlSession;
public List<Employee> getEmps(){
//执行批量
//EmployeeMapper mapper=sqlSession.getMapper(EmployeeMapper.class);
return employeeMapper.getEmps();
}
}
7.oracle中存储过程
查询存储过程
select * from user_source;
<select id="getPageByProcedure" statementType="CALLABLE" databaseId="oracle">
{call hello_test(
#{start,mode=IN,jdbcType=INTEGER},
#{end,mode=IN,jdbcType=INTEGER},
#{count,mode=OUT,jdbcType=INTEGER},
#{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=PageEmp}
)}
</select>
<resultMap type="com.atguigu.mybatis.bean.Employee" id="PageEmp">
<id column="EMPLOYEE_ID" property="id"/>
<result column="LAST_NAME" property="email"/>
<result column="EMAIL" property="email"/>
</resultMap>
测试方法
@Test
public void testProcedure() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
OraclePage page = new OraclePage();
page.setStart(1);
page.setEnd(5);
mapper.getPageByProcedure(page);
System.out.println("总记录数:"+page.getCount());
System.out.println("查出的数据:"+page.getEmps().size());
System.out.println("查出的数据:"+page.getEmps());
}finally{
openSession.close();
}
}
8.类型处理器
步骤
1.创建bean对象
public class Employee {
private Integer id;
private String lastName;
private String email;
private String gender;
private EmpStatus empStatus=EmpStatus.LOGIN;
//省略get和set方法
}
2.创建枚举类
public enum EmpStatus {
LOGIN,LOGOUT,REMOVE
}
3.sql配置文件如下:
<insert id="addEmp" useGeneratedKeys="true" keyProperty="id">
insert into tb1_employee(last_name,email,gender,empStatus)
values(#{lastName},#{email},#{gender},#{empStatus})
</insert>
测试代码如下:
@Test
public void test03() throws Exception{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession=sqlSessionFactory.openSession();
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
Employee employee=new Employee("test_enum","enum@atguigu.com","1");
mapper.addEmp(employee);
System.out.println("保存成功"+employee.getId());
openSession.commit();
openSession.close();
}
默认mybatis在处理枚举对象的时候保存的是枚举的名字:
可以改变使用:EnumOrdinalTypeHandler保存索引的方式来,需要在全局配置文件中做如下的配置:
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumTypeHandler" javaType="com.atguigu.mybatis.bean.EmpStatus"/>
</typeHandlers>
9.自定义类型扩展处理器
public enum EmpStatus {
LOGIN(100,"用户登录"),LOGOUT(200,"用户登出"),REMOVE(300,"用户不存在");
private Integer code;
private String msg;
private EmpStatus(Integer code,String msg) {
this.code=code;
this.msg=msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public static EmpStatus getEmpStatusByCode(Integer code) {
switch(code){
case 100:
return LOGIN;
case 200:
return LOGOUT;
case 300:
return REMOVE;
default:
return LOGOUT;
}
}
}
自定义TypeHandler代码如下:
public class MyEnumEmpStatusTypeHandler implements TypeHandler<EmpStatus>{
@Override
public EmpStatus getResult(ResultSet rs, String columnName) throws SQLException {
int code=rs.getInt(columnName);
EmpStatus status=EmpStatus.getEmpStatusByCode(code);
return status;
}
@Override
public EmpStatus getResult(ResultSet rs, int columnIndex) throws SQLException {
int code=rs.getInt(columnIndex);
EmpStatus status=EmpStatus.getEmpStatusByCode(code);
return status;
}
@Override
public EmpStatus getResult(CallableStatement cs, int columnIndex) throws SQLException {
int code=cs.getInt(columnIndex);
EmpStatus status=EmpStatus.getEmpStatusByCode(code);
return status;
}
//定义当前数据如何保存到数据库中
@Override
public void setParameter(PreparedStatement ps, int i, EmpStatus arg2, JdbcType arg3) throws SQLException {
ps.setString(i,arg2.getCode().toString());
}
}
配置文件配置如下:
<typeHandlers>
<typeHandler handler="com.atguigu.mybatis.typehandler.MyEnumEmpStatusTypeHandler" javaType="com.atguigu.mybatis.bean.EmpStatus"/>
</typeHandlers>