Spring事务管理、Aop

Spring事务管理

增删改,查询没有,只有对数据库造成影响更改。

jdbc: con.setAutoCommit(false);关闭

statement.executeUpdate( ); 自动把数据库语句执行。

最上面的关闭了就一定要 con.comit();/con.rollback();

默认commit();

但是项目中就不能这么自动了。项目中可能一个会有好多sql。
sql1
sql2

一个请求若干个sql。任何一个失败都要恢复到操作之前的状态。
可以
try{
sql1
sql2
con.commit();
}catch(){
con.rollback();
}
保证数据完整性。

1.事务简介

事务是和数据库操作有关概念,可以提交和撤销前面执行的sql操作(针对增删改有效)
使用目的:保证业处理及db数据的完整性。

任何一个sql出现问题。就恢复回去。

整个处理用 try catch出现错误就

  con.rollback();

以上是jdbc

如果是Spring的话

2.Spring提供了对事务管理的支持

支持数据库访问技术API、支持事务管理

采用了AOP(面向切面编程)机制完成事务控制

可以实现在不需要修改之前组件代码情况下的。动态添加,实现事务控制功能

Spring提供了两种事务管理方式:
a.编程式事务管理(编写java代码)
TransactionTemplate
修改每个service。。。

推荐 b.声明式事务管理(编写配置)

XML版本配置
注解版本配置

1.注解版本
先在 Spring配置中配置

<!-- 配置事务管理组件 -->
<bean id ="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dbcp"></property>
</bean>
<!-- 开启事务注解标记@Transactional -->
<!-- 当调用带@Transactional标记的方法时,将txManager事务管理功能切入进去 -->
<tx:annotation-driven transaction-manager="txManager"/>

然后直接在service实现方法前@Transactional就可以了。

事务把一个方法看做一个整体,其中出现一点错误就恢复。不然出现错误,但还在数据库中进行了操作。数据库就有了改变。因为commit是自动的。

XML版本

先配置下
在Spring配置文件头添加

xmlns:aop="http://www.springframework.org/schema/aop"
     xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd

<!-- 配置事务管理组件 -->
<bean id ="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dbcp"></property>
</bean>
<!-- 开启事务注解标记@Transactional -->
<!-- 当调用带@Transactional标记的方法时,将txManager事务管理功能切入进去 -->
<!--  <tx:annotation-driven transaction-manager="txManager"/>-->

<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 指定哪个方法用 -->
<tx:method name="regist"/>
<tx:method name="checkLogin"/>
</tx:attributes>

</tx:advice>

<aop:config>
<aop:pointcut id ="target" expression="within(yunnote.service..*)"/>
<!-- service及其子包都作用aop -->
<aop:advisor advice-ref="txAdvice"
              pointcut-ref="target"/>
</aop:config>

3.Spring对事务管理的控制

a.控制事务可读可写特性
Spring分为可读可写事务和只读事务
默认为可读写,一般只涉及查询操作建议用只读事务。
@Transactional(readOnly=true)
b.控制事务是否回滚
Spring遇到运行时异常会事务回滚,遇到非运行时异常不会回滚。

@Transactional(rollbackFor=IOException.class) 设置如果是IO异常也进行回滚,比如说操作文件
也可以设置一些异常norollbackFor=异常

建议:自定义异常继承运行异常

c.控制事务传播类型
遇到带有事务控制方法调用另一个事务控制方法时,可以选择合适的传播类型
a有f1方法,调用了b中的f2方法。两个都有事务。那么走哪个事务。

public void f1(){
b.f2();
}

f2用f1的事务 REQUIRED
f2用自己的事务 REQUIRED_NEW

默认是 REQUIRED类型,即后者使用前者事务

Spring中常用事务类型
http://blog.csdn.net/fidelhl/article/details/2005294

- PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
- PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_REQUIRED类似的操作。
- PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与

d.控制事务隔离级别
操作并发产生的问题
对同一条记录有并发。
isolation=Isolation.级别
由低到高:
READ_UNCOMMITED//读未提交
READ_COMMITED//读已提交
REPEATABLE_READ//可重复读
SERIALIZABLE//序列化
DEFAULT//默认,根据数据库的隔离级别 例如Oracle

操作一条数据,a查了有可能b给删除了。就是线程问题。就用上面的处理并发。

级别越高安全性越高,但是处理效率越低。
级别越低安全性越差,但是并发处理能力强

选择的默认较多。遇到特殊问题再采用加锁处理

4.Spring AOP应用

AOP编程优点:可以动态将一个组件功能切入到指定的目标方法上去

写一个功能组件,配置添加功能。不用那么更改代码。

面向切面/方面编程

OOP:面向对象编程,侧重点对象设计
AOP:面向切面编程,侧重点切面

AOP编程:更注重于业务逻辑的隔离。将一些共通的处理逻辑和传统的处理逻辑解耦。
单独写成组件,aop作用上去。
例如事务处理,日志记录,异常处理等等

适用环境:
共通处理逻辑
调用时间相同

先开启注解支持

<!-- 开启AOP注解支持 ,@Aspect,@通知标记-->

<aop:aspectj-autoproxy />

然后编写个组件,就是一个类。一定要加载到Spring容器中

package yunnote.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component//扫描,将组建放入Spring容器
@Aspect//将当前组件设置为切面组件
public class ServiceLogger {


    @Before("within(yunnote.service..*)")//
    public void slogger(){
        System.out.println("进入service方法");
    }

}

然后访问,设置的调用service方法就会输出

这里写图片描述

AOP应用

a.要切入什么功能–>切面组件
b.切入的时机–>通知
前置通知(@Before)、后置通知(@AfterReturning)、异常通知(@AfterThrowing)、最终通知(@After)、环绕通知
环绕通知=前置+后置

c.往哪个组件方法切入–>切入点
类型限定表达式
within(类型)
与类型匹配的组件都是目标
within(yunnote.service.UserService)
就是作用到UserService类上。
多个组件就是.*
yunnote.service.*
..*是当前包加其子包
.*是当前包

方法限定表达式
execution(修饰符 返回类型 方法名(参数) 抛出异常)
public list findById(String id)throws Exception
execution(find(..))这个就是只限制方法名是find开头~
也可以类名.方法名
还是execution中写就是最后一定要指到方法名。

还可以用运算符连接
!,&&,||

3点:切面组件、切入时间、切入点

案例:异常处理,当发生异常后,将异常信息记录到文件中。
用AOP的话直接就可以后面添加
a.切入的功能:将异常信息写文件
b.切入的时机:出现异常调用,使用异常通知
@AfterThrowing
c.往哪些组件方法切入:往Controller组件追加
within(yunnote.Controller..*)

yunoteException.log:

package yunnote.aspect;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class ExceptionLogger {

     @AfterThrowing(throwing="e",pointcut="within(yunnote.Controller..*)")
     //参数的e与下面的log的参数要一致
     public void log(Exception e){
          //参数Exception用来接收异常
          //将异常信息写入文件
          System.out.println("记录异常信息 :  "+e);
          try {
              FileWriter fWriter = new FileWriter("c:\\yunnote.log");
              PrintWriter pw = new PrintWriter(fWriter);
              e.printStackTrace(pw);
              pw.flush();
              pw.close();
              fWriter.close();
          } catch (IOException e1) {
              // TODO Auto-generated catch block
              System.out.println("记录异常失败");
              e1.printStackTrace();
          }


     }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值