JDBC-TX-Aspect
JDBC
- xml配置:
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring?serverTimezone=UTC"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!-- 配置jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:component-scan base-package="DAO"></context:component-scan>
jdbcTemplate可以使用set注入也可以注解方式。
2. 增删改查(注意update query参数的使用,还用queryForList的小坑)
private JdbcTemplate jdbcTemplate;
@Override
public int addUser(User user) {
String sql = "insert into user_1(name,account) value(?,?)";
// 储存sql参数
Object[] params = new Object[]{
user.getName(),
user.getAccount()
};
int num = this.jdbcTemplate.update(sql,params);
return num;
}
@Override
public int updateUser(Double account) {
String sql = "update user_1 set account = ?";
int num = this.jdbcTemplate.update(sql,account);
return num;
}
@Override
public int delUser(int id) {
String sql = "delete from user_1 where id = ?";
int num = this.jdbcTemplate.update(sql,id);
return num;
}
@Override
public User findUserById(int id) {
String sql = "select * from user_1 where id = ?";
// RowMapper数据库查询中,如果返回的类型是用户自定义的类型(其实我们在数据库查询中大部分返回的都是自定义的类)则需要包装,
// 如果是Java自定义的类型,如:String则不需要。
RowMapper<User> rowMapper = new BeanPropertyRowMapper<User>(User.class);
return this.jdbcTemplate.queryForObject(sql,rowMapper,id);
}
@Override
public List<User> findAllUsers() {
String sql = "select * from user_1";
RowMapper<User> rowMapper = new BeanPropertyRowMapper<User>(User.class);
// queryForList(sql,class<T>) T单数据类型的,自己定义的Bean不支持
// System.out.println(this.jdbcTemplate.queryForList(sql,String.class));
return this.jdbcTemplate.query(sql,rowMapper);
}
TX事务管理
- 需要包spring-tx数据库的事务管理比如回滚等操作,简化开发者工作量。
- xml配置基于注解和XML
- 注解
<!--注解扫描-->
<context:component-scan base-package="DAO"></context:component-scan>
<context:component-scan base-package="Service"></context:component-scan>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
@Autowired
@Qualifier("userDao")
private userDao userDao;
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,readOnly = false
)
@Override
public void test() {
this.userDao.updateUser(10.0,1);
int i=10/0;//出现错误回滚
}
出现错误后,会自动回滚数据库。
propagation的几个参数
- xml配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" rollback-for=" accountLessException,StockLessException"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* sevice.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"></aop:advisor>
</aop:config>
5.日志操作(注意日志与事务的优先级不然会出现事务回滚吧日志也回滚了,而要求是日志在事务回滚也应该正常进行)
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:component-scan base-package="DAO"></context:component-scan>
<context:component-scan base-package="Service"></context:component-scan>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<aop:aspectj-autoproxy/>
LogDao
@Repository("logDao")
public class LogDaoImpl implements LogDao{
@Autowired
@Qualifier("jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Override
public boolean isLog(Log log) {
String sql = "insert into log(time,result,operation)value(?,?,?)";
Object[] obj = new Object[]{
log.getCreateDate(),log.getReslut(),log.getOperation()
};
int num = this.jdbcTemplate.update(sql,obj);
if(num>0){
return true;
}
return false;
}
}
Log.java
public class Log implements Serializable {
private Long id;
private String operation; //操作的是那个方法
private Date createDate; //操作时间
private String reslut;
@Component("userTx")
public class UserTxImpl implements UserTx{
@Autowired
@Qualifier("userDao")
private userDao userDao;
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,readOnly = false
)
@Override
public void test() {
this.userDao.updateUser(10.0,1);
//int i=10/0;//出现错误回滚
this.userDao.findUserById(2);
}
}
Aspect
@Component
@Aspect
public class myAspect {
@Autowired
@Qualifier("logDao")
private LogDao logDao;
@Pointcut(value = "execution(* Service.UserTxImpl.test())")
private void myPointCut(){
}
@AfterReturning("myPointCut()")
public void myAfterReturn(JoinPoint joinPoint){
Log log = new Log();
String method = joinPoint.getSignature().getName();
log.setOperation(method);
log.setReslut("执行成功");
log.setCreateDate(new Date());
if(logDao.isLog(log)){
System.out.println("记录日志成功");
}else {
System.out.println("记录日志失败");
}
}
@AfterThrowing(value = "myPointCut()",throwing = "e")
public void myAfterThrow(JoinPoint joinPoint, Throwable e){
Log log = new Log();
String method = joinPoint.getSignature().getName();
log.setOperation(method);
log.setReslut("执行失败");
log.setCreateDate(new Date());
if(logDao.isLog(log)){
System.out.println("记录日志成功");
}else {
System.out.println("记录日志失败");
}
}
}
如图执行回滚操作应该有79的日志记录,他却把日志也回滚了
原因:
考虑其优先级Order()
<tx:annotation-driven transaction-manager="transactionManager" order="2"></tx:annotation-driven>
@Order(1)
@Component
@Aspect
public class myAspect {
结果
Z