JAVAEE之Spring学习(三)---通过aop切面实现事务处理
2017-08-22 14:09
459 查看
需求:通过切面给项目中的service添加事务处理,让数据库表1添加用户失败后回滚,表2无法添加数据
思想:通过aop切面拦截service下的reg()方法,在拦截之前开启事务再进行dao调用,进行事务处理
需要注意的地方:在spring方式下获得到的datasource中的getconnection方法还没有进行拦截,在dao层,是通过queryrunner自动调用getconnection()进行提交,所以要将getconnection()做成单线程形式
service:package cn.hncu.stud.service; import java.sql.SQLException; import cn.hncu.stud.dao.IStudaoa; import cn.hncu.stud.domain.User; public class serviceimpl implements IStudentService { IStudaoa dao1 = null; IStudaoa dao2 = null; public IStudaoa getDao1() { return dao1; } public void setDao1(IStudaoa dao1) { this.dao1 = dao1; } public IStudaoa getDao2() { return dao2; } public void setDao2(IStudaoa dao2) { this.dao2 = dao2; } // 注入 @Override public void reg(User user) throws SQLException { dao1.reg(user); dao2.reg(user); } }
web.xml:将Spring容器放入servletContext中
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value> <!-- 如果有路径要用"/"开始 --> classpath:beans.xml, /WEB-INF/applicationContext.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>StudServlet</servlet-name> <servlet-class>cn.hncu.stud.servlet.StudServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>StudServlet</servlet-name> <url-pattern>/StudServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
servlet:通过ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());获取spring容器
package cn.hncu.stud.servlet; import java.io.IOException; import java.io.PrintWriter; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import cn.hncu.stud.domain.User; import cn.hncu.stud.service.IStudentService; public class StudServlet extends HttpServlet { private IStudentService service = null; @Override public void init() throws ServletException { // 获取web项目中的spring容器 ApplicationContext ctx = WebApplicationContextUtils .getWebApplicationContext(getServletContext()); service = ctx.getBean("service", IStudentService.class); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); User user = new User(); user.setName(name); try { service.reg(user); request.getSession().setAttribute("user", user); request.getRequestDispatcher("/jsps/show.jsp").forward(request, response); } catch (SQLException e) { e.printStackTrace(); } } }
applicationContext:用于配置dataSource和拦截getconnection的公共Spring容器配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> </bean> <!-- 切面=切点+通知 --> <bean id="advisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor"> <!-- 切点 --> <property name="expression"> <value> execution( void cn.hncu.stud..serviceimpl.reg(..) ) </value> </property> <property name="advice"> <bean class="cn.hncu.stud.utils.AroundAdvice"> <property name="data" ref="dataSource"></property> </bean> </property> </bean> <!-- 切面=切点+通知 --> <bean id="advisor1" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor"> <!-- 切点 --> <property name="expression"> <value>execution(* *..*.getConnection()) </value> </property> <property name="advice"> <bean class="cn.hncu.stud.utils.ConAdvice"> </bean> </property> </bean> <context:property-placeholder location="WEB-INF/conf/jdbc.properties" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> <property name="driverClass" value="${driver}"> </property> <property name="url" value="${url}"></property> <!-- ${username}是系统默认的变量--> <property name="username" value="${uname}"></property> <property name="password" value="${password}"></property> </bean> </beans>
用于拦截getconnection方法的切面:
package cn.hncu.stud.utils; import java.lang.reflect.Method; import java.sql.Connection; import javax.sql.DataSource; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodProxy; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class ConAdvice implements MethodInterceptor { private ThreadLocal<Connection> t1 = new ThreadLocal<Connection>(); DataSource data = null; public DataSource getData() { return data; } public void setData(DataSource data) { this.data = data; } @Override public Object invoke(MethodInvocation inv) throws Throwable { Connection con = t1.get(); if (con == null) { // 往本地线程池中放一个被屏蔽掉close()方法的con对象 final Connection con0 = ((Connection) inv.proceed());// 当前被拦截的是getconnection返回的是一个con // 对con0进行代理(屏蔽close()) Callback callback = new net.sf.cglib.proxy.MethodInterceptor() { @Override public Object intercept(Object proxiedObj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if (method.getName().equals("close")) { return null; } return method.invoke(con0, args); } }; // 生成代理后的对象 con = (Connection) Enhancer.create(Connection.class, callback); t1.set(con);// 把代理后的对象放进去 } return con; } }
beans.xml:用于配置stud模块下的类的关联
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="studDao" class="cn.hncu.stud.dao.IStuJDBCDAO"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="studDao2" class="cn.hncu.stud.dao.IStuJDBCDAO2"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="service" class="cn.hncu.stud.service.serviceimpl"> <property name="dao1" ref="studDao"></property> <property name="dao2" ref="studDao2"></property> </bean> </beans>
AroundAdvice:进行service类的拦截:
package cn.hncu.stud.utils; import java.sql.Connection; import javax.sql.DataSource; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class AroundAdvice implements MethodInterceptor, ApplicationContextAware { ApplicationContext ctx = null; DataSource data = null; public DataSource getData() { return data; } public void setData(DataSource data) { this.data = data; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { Connection con = data.getConnection(); con.setAutoCommit(false); System.out.println("开启事务"); // 放行 try { Object returnValue = invocation.proceed(); con.commit(); return returnValue; } catch (Exception e) { con.rollback(); System.out.println("事务回滚"); } finally { con.setAutoCommit(true); } return null; } @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException { this.ctx = ctx; } }
这样就成功通过spring实现数据库的事务处理
相关文章推荐
- Spring aop事务代理对象通过TransactionInterceptor处理目标方法事务过程,cglib方式
- Spring 4.0 学习日记(9) ---XML配置实现AOP切面
- Spring 通过注解方式实现AOP切面编程
- Spring aop 通过获取代理对象实现事务切换
- spring学习(八)—AOP通过注解方式实现
- spring aop事务通知(切面异常处理)
- Spring-通过xml配置文件实现切面(AOP)
- Spring面向切面编程——Spring实现AOP方式——通过注解实现
- spring3.0 aop的annotation实现切面,新手学习
- spring学习(七)—AOP通过配置文件方式实现
- JavaEE进阶知识学习-----SpringBootWeb进阶-7-AOP处理请求知识
- spring学习笔记(23)基于tx/aop配置切面增强事务
- 【Java EE 学习 77 上】【数据采集系统第九天】【通过AOP实现日志管理】【通过Spring石英调度动态生成日志表】【日志分表和查询】
- Spring面向切面编程——Spring实现AOP方式——通过Spring API实现
- Spring 4.0 学习日记(8) ---AOP切面注解实现五种通知
- spring学习笔记7--使用spring进行面向切面的(AOP)编程(1)注解方式实现
- 通过spring的aop注解实现所有方法异常的捕获处理,sqlite SQLITE_BUSY异常
- JAVAEE之Spring学习(三)---aop切面(一)
- 学习笔记:spring与hibernate整合(采用aop来管理事务来实现声明式事务)
- Spring AOP切面实现:异常处理