Spring使用AOP来完成声明式的事务管理 有annotation和xml两种形式
代码和上一篇基本相近,再贴一遍
两个实体类
package com.ouc.wkp.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity(name = "t_log") public class Log { private int id; private String msg; @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
package com.ouc.wkp.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity(name="user2") public class User2 { private int id; private String username; @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } @Column public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
两个接口DAO
package com.ouc.wkp.dao; import com.ouc.wkp.model.Log; public interface LogDAO { public void save(Log log); }
package com.ouc.wkp.dao; import com.ouc.wkp.model.User2; public interface UserDAO { public void save(User2 user2); public void delete(); }
接口实现
package com.ouc.wkp.dao.impl; import java.sql.Connection; import java.sql.SQLException; import javax.annotation.Resource; import javax.sql.DataSource; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.stereotype.Component; import com.ouc.wkp.dao.UserDAO; import com.ouc.wkp.model.User2; @Component("u") public class UserDAOImpl implements UserDAO { // private DataSource dataSource; // // public DataSource getDataSource() { // return dataSource; // } // // @Resource // public void setDataSource(DataSource dataSource) { // this.dataSource = dataSource; // } private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } @Resource public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } @Override public void save(User2 user2) { // Hibernate // JDBC // XML // NetWork // System.out // .println("session factory class:" + sessionFactory.getClass()); Session s = sessionFactory.getCurrentSession(); // s.beginTransaction(); s.save(user2); // s.getTransaction().commit(); // System.out.println("user saved!"); } @Override public void delete() { // TODO Auto-generated method stub } }
package com.ouc.wkp.dao.impl; import javax.annotation.Resource; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.stereotype.Component; import com.ouc.wkp.dao.LogDAO; import com.ouc.wkp.model.Log; @Component("logDAO") public class LogDAOImpl implements LogDAO { private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } @Resource public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } @Override public void save(Log log) { Session s = sessionFactory.getCurrentSession(); s.save(log); // throw new RuntimeException();//事务会回滚 spring配置后省去了try catch } }
package com.ouc.wkp.service; import javax.annotation.Resource; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.ouc.wkp.dao.LogDAO; import com.ouc.wkp.dao.UserDAO; import com.ouc.wkp.model.Log; import com.ouc.wkp.model.User2; @Component("userService") public class UserService { private UserDAO userDAO; private LogDAO logDAO; public LogDAO getLogDAO() { return logDAO; } @Resource(name = "logDAO") public void setLogDAO(LogDAO logDAO) { this.logDAO = logDAO; } public User2 getUser(int id) { return null; } public void init() { System.out.println("init"); } // @Transactional(propagation = Propagation.REQUIRED) // 事务的传播特性 默认REQUIRED // readOnly=true只读的 spring会进行优化 // 声明式事务管理 进行事务 public void add(User2 user2) { userDAO.save(user2); Log log = new Log(); log.setMsg("a user saved"); logDAO.save(log); } public UserDAO getUserDAO() { return userDAO; } @Resource(name = "u") public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } public void destroy() { System.out.println("destroy"); } }
使用注解时在对应的方法前加上@Transactional(propagation = Propagation.REQUIRED)
(propagation = Propagation.REQUIRED)可以省去,因为事务的传播特性 默认为REQUIRED
配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 4 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context-3.1.xsd 9 http://www.springframework.org/schema/aop 10 http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 11 http://www.springframework.org/schema/tx 12 http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> 13 <context:annotation-config /> 14 <!-- 使用注解需要下面四条 --> 15 <!-- xmlns:context="http://www.springframework.org/schema/context" --> 16 <!-- http://www.springframework.org/schema/context --> 17 <!-- http://www.springframework.org/schema/context/spring-context-3.1.xsd"> --> 18 <!-- <context:annotation-config /> --> 19 20 <!-- 使用aop需要一下 --> 21 <!-- xmlns:aop="http://www.springframework.org/schema/aop" --> 22 <!-- http://www.springframework.org/schema/aop --> 23 <!-- http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> --> 24 <!-- <aop:aspectj-autoproxy /> --> 25 26 <!-- 使用事务 --> 27 <!-- xmlns:tx="http://www.springframework.org/schema/tx" --> 28 <!-- http://www.springframework.org/schema/tx --> 29 <!-- http://www.springframework.org/schema/tx/spring-tx-2.5.xsd --> 30 <!-- <tx:annotation-driven transaction-manager="txManager"/> --> 31 32 33 <!-- 扫描 --> 34 <context:component-scan base-package="com.ouc.wkp"></context:component-scan> 35 36 <aop:aspectj-autoproxy /> 37 38 <bean 39 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 40 <property name="locations"> 41 <value>classpath:jdbc.properties</value> 42 </property> 43 </bean> 44 45 <bean id="dataSource" destroy-method="close" 46 class="org.apache.commons.dbcp.BasicDataSource"> 47 <property name="driverClassName" value="${jdbc.driverClassName}" /> 48 <property name="url" value="${jdbc.url}" /> 49 <property name="username" value="${jdbc.username}" /> 50 <property name="password" value="${jdbc.password}" /> 51 </bean> 52 53 <bean id="sessionFactory" 54 class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 55 <property name="dataSource" ref="dataSource" /> 56 <!-- <property name="annotatedClasses"> --> 57 <!-- <list> --> 58 <!-- <value>com.ouc.wkp.model.User2</value> --> 59 <!-- <value>com.ouc.wkp.model.Log</value> --> 60 <!-- </list> --> 61 <!-- </property> --> 62 <property name="packagesToScan"> 63 <list> 64 <value>com.ouc.wkp.model</value> 65 </list> 66 </property> 67 <property name="hibernateProperties"> 68 <props> 69 <prop key="hibernate.dialect"> 70 org.hibernate.dialect.MySQLDialect 71 </prop> 72 <prop key="hibernate.show_sql">true</prop> 73 </props> 74 </property> 75 </bean> 76 77 78 <!-- Spring使用AOP来完成声明式的事务管理 --> 79 <bean id="txManager" 80 class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 81 <!-- <property name="dataSource" ref="dataSource" /> --> 82 <property name="sessionFactory" ref="sessionFactory" /> 83 </bean> 84 85 <tx:annotation-driven transaction-manager="txManager" /> 86 87 <aop:config> 88 <aop:pointcut expression="execution(public * com.ouc.wkp.service..*.*(..))" 89 id="businessService" /> 90 <!-- 在此pointcut上加上txAdvice建议 --> 91 <aop:advisor advice-ref="txAdvice" pointcut-ref="businessService" /> 92 </aop:config> 93 94 <tx:advice id="txAdvice" transaction-manager="txManager"> 95 <tx:attributes> 96 <tx:method name="getUser" read-only="true" /> 97 <tx:method name="add*" propagation="REQUIRED" /> 98 </tx:attributes> 99 </tx:advice> 100 101 </beans>
两个地方需要注意
1.这种方式可以省去写多个model类的配置
<property name="packagesToScan">
<list>
<value>com.ouc.wkp.model</value>
</list>
</property>
2.
bean定义了一个事务管理,注入sessionFactory。
紧接着规定事务管理器为txManager即上面bean中定义的。
<aop:config>定义一个切面,在这个切面加上advice。
最后定义一个advice,
<tx:method name="getUser" read-only="true" />表示getUser方法是只读的并且进行了声明式事务管理。readonly可以提高程序效率。
<tx:method name="add*" propagation="REQUIRED" />标识为以add开头的方法添加事务。
测试类
package com.ouc.wkp.test; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.ouc.wkp.model.User2; import com.ouc.wkp.service.UserService; //Dependency Injection //Inverse of Control public class UserServiceTest { @Test public void testAdd() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( "beans.xml"); UserService service = (UserService) ctx.getBean("userService"); User2 user2=new User2(); user2.setId(1); user2.setUsername("ttyy"); System.out.println(user2); service.add(user2); ctx.destroy(); } }
如果出错则事务回滚,两条记录都增加失败。