Spring框架学习之四

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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值