spring事務管理方式,aop


達內12 note unit 09 01

1.spring事務管理

2.spring提供了對事務管理支持

spring采用aop機制完成事務控制

可以實現在不修改原有組件代碼情況下實現事務控制功能。

 

spring提供了兩種事務管理方式:

a。編程式事務管理(編寫java代碼)

  TransactionTemplate

b.聲明式事務管理(編寫配置,大家都用這種)

  xml版本配置

  注解版本配置

  --配置DataSourceTransactionManager

  --開啟事務注解配置<tx:annotation>

  --在目標組件方法前添加@Transactional

 

注解版本例子:

例如UserServiceImpl中的regist注冊方法需要事務:

第一步,我們現在applicationContext.xml中配置事務管理組件

<!--  配置事務管理組件 -->

<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注解

package org.alexhe.note.service;

 

import javax.annotation.Resource;

 

import org.alexhe.note.dao.IUserDao;

import org.alexhe.note.entity.NoteResult;

import org.alexhe.note.entity.User;

import org.alexhe.note.util.NoteUtil;

import org.springframework.stereotype.Service;

 

@Service("userService")

@Transactional//這里加入事務注解

public class UserServiceImpl implements IUserService{

@Resource

private IUserDao userDao;//注入

@Override

public NoteResult checkLogin(String name, String pwd) throws Exception {

// TODO Auto-generated method stub

NoteResult result=new NoteResult();

User user=userDao.findByName(name);

if(user==null){

result.setStatus(1);

result.setMsg("用戶名不存在");

return result;

}

 

String md5_pwd=NoteUtil.md5(pwd);

if(!user.getCn_user_password().equals(md5_pwd)){

result.setStatus(2);

result.setMsg("密碼不正確");

return result;

}

result.setStatus(0);

result.setMsg("用戶名和密碼正確");

result.setData(user.getCn_user_id());//返回userid

return result;

}

@Override

public NoteResult regist(String name, String password, String nickname) throws Exception {

NoteResult result=new NoteResult();

//檢測用戶名是否被占用

User has_user=userDao.findByName(name);

if(has_user!=null){

result.setStatus(1);

result.setMsg("用戶名已被占用");

return result;

}

//注冊

User user=new User();

user.setCn_user_name(name);

user.setCn_user_desc(nickname);

String md5_pwd=NoteUtil.md5(password);

user.setCn_user_password(md5_pwd);//設置加密的密碼

String userId=NoteUtil.createId();

user.setCn_user_id(userId);//設置userid

//調用userDao保存

userDao.save(user);

result.setStatus(0);

result.setMsg("注冊成功");

return result;

}

 

}

 

 

xml版本配置例子:(配置比注解版復雜)

第一步,我們現在applicationContext.xml中配置事務管理組件,記得xml里加入aop的頭

<!--  配置事務管理組件 -->

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

  <property name="dataSource" ref="dbcp"></property>

</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">

  <tx:attributes><!--  哪些方法用事務,就寫在里面 -->

    <tx:method name="regist"/>

    <tx:method name="checkLogin"/>

    <tx:method name="add*"/> <!--  以add開頭的所有方法 -->

   <!--  <tx:method name="*"/> <!--  所有方法都加注釋 -->

  </tx:attributes>

</tx:advice>

<aop:config>

  <aop:pointcut id="target" expression="within(org.alexhe.note.service..*)"/> <!--  expression代表哪個組件,作用在哪些組件上,這里代表service包及其下面的所有組件-->

  <aop:advisor advice-ref="txAdvice" pointcut-ref="target"/> 

</aop:config>

 

 

3.Spring對事務管理的控制

a。控制事務可讀可寫特性

Spring分為可讀寫事務和只讀事務。默認為可讀寫,一般只涉及查詢操作,建議用只讀事務

@Transactional(readOnly=true)

 

b.控制事務是否回滾

Spring遇到runtimeException異常,會回滾。遇到非運行時異常,不會回滾。

@Transactional(readOnly=true,rollbackFor=IOException.class)   這樣遇到IOException也會發生回滾。

 

建議:自定義異常繼承自RuntimeException繼承

public class MyException extends RuntimeException   

 

c。控制事務傳播類型

 遇到帶有事務控制方法調用另一個事務控制方法時,可以選擇合適的傳播類型,默認是required類型,后者使用前者事務。

 

d。控制事務隔離級別

@Transactional(readOnly=true, isolation=Isolation.READ_COMMITED);

由低到高如下:

READ_UNCOMMITED讀未提交

READ_COMMITED讀已提交

REPEATABLE_READ可重復讀

SERIALIZABLE序列化操作

DEFAULT默認,根據數據庫隔離級別自動選擇,

 

4.spring aop應用

aop編程優點:可以動態將一個組件功能切入到指定的目標方法上。可以使結構更加靈活,也能實現組件重復利用。

aop編程:更注重於業務邏輯隔離,將一些共通處理邏輯和傳統處理邏輯解耦。

例如事務處理,日志記錄,異常處理等等。

 

適用環境:

  --共通處理邏輯

  --調用時機相同

 

例子,用xml配置方式,往controller上加方法:

1.新建了一個aspect包(非必須)

2.包里新建一個類,然后新建一個clogger方法。表示加上日志功能。

3.spring的文件里加配置,把需要aop的controller加上第二步類里的方法

package org.alexhe.note.aspect;

 

public class NoteLogger {

 

public void clogger(){

System.out.println("進入Controller處理");

}

}

 

 

spring的配置:

<!-- aop示例 -->

<bean id="noteLogger" class="org.alexhe.note.aspect.NoteLogger"></bean>

<aop:config>

<!-- 把上面的noteLogger定義為切面組件 -->

<aop:aspect ref="noteLogger">

<!-- 什么時候,向哪些方法上切入 --><!-- 在controler包及其子包下,所有執行的方法前,加入clogger方法  -->

<aop:before method="clogger" pointcut="within(org.alexhe.note.controller..*)"/> 

</aop:aspect>  

</aop:config>

 

例子,用注解方式,往service層加方法:

spring配置不用上面這一坨,只要加上:

<!-- 開啟aop注解支持,@Aspect,@通知標記 -->

<aop:aspectj-autoproxy />

 

java類:

package org.alexhe.note.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(org.alexhe.note.service..*)")//service下面所有方法加入這個slooger方法

public  void slogger(){

System.out.println("進入service方法");

}

}

 

=====AOP應用=====

a。要切入什么功能

b。要切入的時機,什么時候切入,通知。

  前置通知,在原有方法前插入新功能。@Before

  后置通知,在執行完原有方法后,調入新的切面方法。@AfterReturning

  異常通知,在原有方法出異常了,調入新的切面方法。@AfterThrowing

  最終通知,不管有沒有異常,最終都要走他。@After

  環繞通知=前置+后置

try{

  前置通知@Before

  //目標方法處理

  后置通知@AfterReturning

}catch(){

  異常通知@AfterThrowing

}finally{

  最終通知@After

}

 

c。往那些組件方法切入-->切入點

  --類型限定表達式

  within(類型)

  與類型匹配的組件都是目標

  within(org.service.UserService)

  within(org.service.*) 僅限於當前包下

  within(org.service..*) 當前包和子包下

 

  --方法限定表達式

  execution(修飾符 返回類型 方法名(參數) 拋出異常)     返回類型和方法名參數是必須的,其他可以省略

  execution(* find*(..))     必須是find開頭的方法,參數返回值不限制

  execution(* org.service.UserService.regist*(..))   

  execution(* org.service..*.*(..))   

 

上述表達式可以使用 !,&&,|| 運算符連接。

 

案例:將異常信息寫入文件

package org.alexhe.note.aspect;

 

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.AfterThrowing;

import org.springframework.stereotype.Component;

 

@Component//掃描,將組件掃描到Spring容器

@Aspect//將當前組件設置為切面組件

public class ExceptionLogger {

 

@AfterThrowing(throwing="e",pointcut="within(org.alexhe.note.service..*)")//service下面所有方法加入這個log方法

public  void log(Exception e){

System.out.println(e);

}

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM