Spring第三天——AOP注解實現與事務管理


  大致內容:

    aspectJ的aop操作(基於注解,對比day02配置操作)(會用)
    *jdbcTemplate操作(實現CRUD)
    *spring配置連接池
    *spring事務管理

一、AspectJ的基於注解的AOP操作

 

    (day02的配置回顧,略顯麻煩,配置稍多)

    建立項目記得導入day02操作aop的那些包(如果是復制項目一定要修改項目的context name)
    再把配置文件拿過來

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> 
    <!-- 開啟aop代理(開啟aop操作) -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!-- 配置創建對象 -->
    <bean id="book" class="cn.aop.Book"></bean>
    <bean id="buyBook" class="cn.aop.BuyBook"></bean>
</beans>

 

    建立兩個類:Book 和 BuyBook,這里我們使用的是配置文件中創建,這里第二次看spring覺得應該改為掃描包,然后加注解@Componet等注解來完成把類交給spring容器來管理(右上角的小s圖標),開發更快,更方便!

  依舊使用配置文件創建對象,開啟aop操作
    在增強的類上使用注解實現增強的操作

    在增強的類上使用注解完成aop操作
    在類上加@Aspect
    在方法上加真正的注解
  @Before 前置通知
  @AfterReturning 后置通知
  @Around 環繞通知
  @AfterThrowing 拋出通知
  @After 最終通知

 

  value屬性值為原來的表達式的值
  (表達式寫法需要注意)
  其它項目不用時請將其關閉!

package cn.aop; public class Book { public void buy(){ System.out.println("Book.buy"); } }
package cn.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class BuyBook { //方法上使用注解完成真正的增強操作
    @Before(value="execution(* cn.aop.Book.*(..))") public void before1(){ System.out.println("BuyBook.before"); } }

  //任何擁有@AspectJ的注解不能被spring自動檢測發現,需要配合@Component注解配合使用(或者使用xml的bean的配置方式)

  //定義切入點見day02

  【更新】:(例如拿到原方法的參數:通過JoinPoint)

package com.atguigu.spring.aop; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * AOP 的 helloWorld * 1. 加入 jar 包 * com.springsource.net.sf.cglib-2.2.0.jar * com.springsource.org.aopalliance-1.0.0.jar * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar * spring-aspects-4.0.0.RELEASE.jar * * 2. 在 Spring 的配置文件中加入 aop 的命名空間。 * * 3. 基於注解的方式來使用 AOP * 3.1 在配置文件中配置自動掃描的包: <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan> * 3.2 加入使 AspjectJ 注解起作用的配置: <aop:aspectj-autoproxy></aop:aspectj-autoproxy> * 為匹配的類自動生成動態代理對象. * * 4. 編寫切面類: * 4.1 一個一般的 Java 類 * 4.2 在其中添加要額外實現的功能. * * 5. 配置切面 * 5.1 切面必須是 IOC 中的 bean: 實際添加了 @Component 注解 * 5.2 聲明是一個切面: 添加 @Aspect * 5.3 聲明通知: 即額外加入功能對應的方法. * 5.3.1 前置通知: @Before("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))") * @Before 表示在目標方法執行之前執行 @Before 標記的方法的方法體. * @Before 里面的是切入點表達式: * * 6. 在通知中訪問連接細節: 可以在通知方法中添加 JoinPoint 類型的參數, 從中可以訪問到方法的簽名和方法的參數. * * 7. @After 表示后置通知: 在方法執行之后執行的代碼. */

//通過添加 @Aspect 注解聲明一個 bean 是一個切面!
@Aspect @Component public class LoggingAspect { @Before("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); } @After("execution(* com.atguigu.spring.aop.*.*(..))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } }

二、jdbcTemplate操作


  spring是一站式的框架,對應javaEE三層框架都有不同的解決方案,jdbcTemplate就是對應於DAO層的
  spring對不同的持久化層技術都作了不同的支持
  JDBC === jdbcTemplate
  Hibernate === HibernateTemplate (少寫很多的操作)
  MyBatis JPA等都有不同的支持

  jdbcTemplate使用(CRUD操作)和DBUtils比較類似(但是並沒有DBUtils方便,只是jdbc模板是spring封裝好的)

  這里可以參見博友的博客:http://www.cnblogs.com/caoyc/p/5630622.html

    像這里批量操作,適用於SQL語句相同,而參數不同(注意參數)

  具體的使用:
    准備工作:
      導包:spring-jdbc spring-tx(事務)
    說到數據庫,當然少不了最最最基本驅動jar包

           

  添加:
    依賴連接池獲得連接,創建對象,設置數據庫信息
    創建jdbcTemplate對象,設置數據源

  建表
    使用jdbcTemplate實現操作(和DBUtils是非常像的)
    增加修改在類中,刪除不再贅述,只是SQL語句的差異
    當然,具體的信息可以通過log4j看到,log4j的介紹在另外的博文中作介紹

package cn.jdbc; import org.junit.Test; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; public class JDBCDemo01 { @Test public void add(){ //創建對象,設置數據庫信息
        DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //本機時可以寫成jdbc:mysql:///mydb
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydb"); dataSource.setUsername("root"); dataSource.setPassword("root"); //創建jdbcTemplate對象,設置數據源
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); //使用jdbcTemplate實現操作(已經建表)
        String sql = "insert into user values(?,?)"; //注意使用的方法,dbutils調的也是update方法,參數是SQL和可變參數
        int i = jdbcTemplate.update(sql, "lulu","123"); System.out.println(i); } //測試模板的修改方法,這是SQL語句的方法
 @Test public void update(){ //創建對象,設置數據庫信息
                DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //本機時可以寫成jdbc:mysql:///mydb
                dataSource.setUrl("jdbc:mysql://localhost:3306/mydb"); dataSource.setUsername("root"); dataSource.setPassword("root"); //創建jdbcTemplate對象,設置數據源
                JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); String sql = "update user set username=? where username=?"; int i = jdbcTemplate.update(sql, "lucy","lulu"); System.out.println(i); } }

  *查詢:查詢是重點
    (QueryRunner runner = new QueryRunner(dataSource);
    runner.query(sql,new BeanHandler<User>(User.class));
    具體的ResultSetHandler可參考DBUtils部分)
    使用jdbcTemplate實現查詢時,有接口RowMapper,但沒有像dbutils一樣提供實現類
    需要自己提供實現類(學習這個的目的不是為了更加方便,而是一般的,如果允許,盡量使用少的技術)
    回顧JDBC底層實現查詢結果,將結果集封裝到對象中
  查詢的具體實現:
    1.返回某一個值
      queryForObject(sql, requiredType) 返回類型,如Integer.class(統計記錄數)
    2.返回一個對象
      jdbcTemplate.queryForObject(sql, rowMapper, args)
      第二個是結果集的處理,第三個是可變參數
      第二個接口可以寫匿名內部類,當然也可以單獨寫個類(更直觀)

    RowMapper實現類
      class MyRowMapper implements RowMapper<User>{

      public User mapRow(ResultSet arg0, int arg1) throws SQLException {
    第二個 int arg1 表示行號(結果集的行號)
      return null;
    3.返回一個集合
      jdbcTemplate.query(sql, rowMapper, args)
      第三個是可變參數(當然有可省略的重載方法),返回的是集合
      數據封裝也要自己寫(不支持級聯屬性,畢竟是作為一個小工具,而不是框架)

 給出一個Demo如下(注意最后給出的實現類):

package cn.jdbc; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.junit.Test; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.datasource.DriverManagerDataSource; public class JDBCDemo02 { //演示查詢返回某個值
 @Test public void count(){ //創建對象,設置數據庫信息
                DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //本機時可以寫成jdbc:mysql:///mydb
                dataSource.setUrl("jdbc:mysql://localhost:3306/mydb"); dataSource.setUsername("root"); dataSource.setPassword("root"); //創建jdbcTemplate對象,設置數據源
                JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); String sql = "SELECT COUNT(*) FROM user"; Integer i = jdbcTemplate.queryForObject(sql, Integer.class); System.out.println(i); } //演示返回對象
 @Test public void obj(){ //創建對象,設置數據庫信息
        DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //本機時可以寫成jdbc:mysql:///mydb
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydb"); dataSource.setUsername("root"); dataSource.setPassword("root"); //創建jdbcTemplate對象,設置數據源
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); String sql = "select * from user where username=?"; //和dbutils類似,也是new一個處理器,不過這里需要自己實現
        User user = jdbcTemplate.queryForObject(sql, new MyRowMapper(), "mary"); System.out.println(user); } //返回對象集合
 @Test public void objlist(){ //創建對象,設置數據庫信息
                DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //本機時可以寫成jdbc:mysql:///mydb
                dataSource.setUrl("jdbc:mysql://localhost:3306/mydb"); dataSource.setUsername("root"); dataSource.setPassword("root"); //創建jdbcTemplate對象,設置數據源
                JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); String sql = "select * from user"; List<User> list = jdbcTemplate.query(sql, new MyRowMapper()); for (User user : list) { System.out.println(user.getUsername()); } } }
//屬性封裝需要自己實現
class MyRowMapper implements RowMapper<User>{ public User mapRow(ResultSet rs, int num) throws SQLException { String username = rs.getString("username");//使用索引更高效 String password = rs.getString("password"); User user = new User(); user.setUsername(username); user.setPassword(password); return user; } }

 

三、spring配置連接池和dao使用jdbcTemplate

 


  導包:
    c3p0的兩個jar包 c3p0 和依賴包 mchange
    在配置連接池(原始方式見數據庫連接池部分)
    ComboPooledDataSource這個類本身里面就有屬性和相關的set()方法
    可以使用之前學的屬性注入!屬性注入注入的屬性就是參考set()方法命名規范

bean1.xml配置文件:

  可以創建service dao 進行稍微正式的測試,順便復習屬性注入
  給JdbcTemplate需要傳入dataSource ,需要注意注意這個
  service注入dao
  dao注入jdbcTemplate
  jdbcTemplate注入dataSource

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> 
    <!-- 配置c3p0連接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 進行屬性注入 -->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <!-- 在配置中配置依賴注入 -->
    <bean id="userService" class="cn.c3p0.UserService">
        <!-- service中注入dao -->
        <property name="dao" ref="dao"></property>
    </bean>
    <bean id="dao" class="cn.c3p0.UserDao">
        <!-- dao中注入jdbcTemplate -->
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
    <!-- 創建模板對象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 給模板注入dataSource,具體可以看源碼了解(set()方法等) -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>

 //常用的RowMapper,列映射器,有默認實現類 BeanPropertiesRowMapper

UserDao:【更新】:這里可以使用@Autowired進行注入(底層是byType)(可以用在屬性,用在set方法,用在構造器

  extends jdbcDaoSupport 不推薦(不能使用注解)

package cn.c3p0; import org.springframework.jdbc.core.JdbcTemplate; public class UserDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void add() { //在這里使用jdbcTemplate new模板對象的過程都交給spring
        String sql = "insert into user values(?,?)"; int i = jdbcTemplate.update(sql, "lilei","112"); System.out.println(i); } }

UserService:

package cn.c3p0; public class UserService { private UserDao dao; public void setDao(UserDao dao) { this.dao = dao; } public void add(){ System.out.println("service.add"); dao.add(); } }

//可以使用JDBC的具名參數(好處是可讀性強了,但帶來了代碼量)(需要配置相關的bean)

public class JDBCTest {
    
    private ApplicationContext ctx = null;
    private JdbcTemplate jdbcTemplate;
    private EmployeeDao employeeDao;
    private DepartmentDao departmentDao;
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    
    {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        employeeDao = ctx.getBean(EmployeeDao.class);
        departmentDao = ctx.getBean(DepartmentDao.class);
        namedParameterJdbcTemplate = ctx.getBean(NamedParameterJdbcTemplate.class);
    }
    
    /**
     * 使用具名參數時, 可以使用 update(String sql, SqlParameterSource paramSource) 方法進行更新操作
     * 1. SQL 語句中的參數名和類的屬性一致!
     * 2. 使用 SqlParameterSource 的 BeanPropertySqlParameterSource 實現類作為參數. 
     */
    @Test
    public void testNamedParameterJdbcTemplate2(){
        String sql = "INSERT INTO employees(last_name, email, dept_id) "
                + "VALUES(:lastName,:email,:dpetId)";
        
        Employee employee = new Employee();
        employee.setLastName("XYZ");
        employee.setEmail("xyz@sina.com");
        employee.setDpetId(3);
        
        SqlParameterSource paramSource = new BeanPropertySqlParameterSource(employee);
        namedParameterJdbcTemplate.update(sql, paramSource);
    }
View Code

 

四、spring的事務管理

 

  (不用像之前Hibernate一樣寫大堆的事務的代碼)
    事務的回顧見JDBC部分
    事務的概念
    事務的特性
    事務的隔離性產生的問題
  spring的事務管理主要有兩種方式:(前面的AOP的原理)
    1.編程式事務管理(自己寫代碼,用的少)
    2.聲明式事務管理(配置文件實現,注解方式實現(簡單易用))
  相關的API:
    PlatformTransactionManager :spring的事務管理器接口,為不同的持久化框架提供了不同的實現類
                    例如模板的實現類:dataSourceTransactionManager
    Hibernate的實現類:HibernateTransactionManager
  無論注解還是配置文件都要配置事務管理器

  搭建轉賬的環境演示事務管理的操作:
  建表,添加一些數據
  創建service和dao以及注入關系的完成(區分業務層和持久層的區別,業務層只處理業務,持久層只和數據庫打交道)

Service:

package cn.acount; import org.springframework.transaction.annotation.Transactional; @Transactional public class AcountService { private AcountDao dao; public void setDao(AcountDao dao) { this.dao = dao; } //service調dao的方法完成邏輯
    public void acountMoney(){ dao.decrese(); //int i = 1/0;
 dao.increse(); } }

Dao:

package cn.acount; import org.springframework.jdbc.core.JdbcTemplate; public class AcountDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } //減少錢的方法
    public void decrese(){ String sql = "update acount set money=money+? where name=?"; jdbcTemplate.update(sql, -1000,"小王"); } //增加錢的方法
    public void increse(){ String sql = "update acount set money=money+? where name=?"; jdbcTemplate.update(sql, 1000,"小李"); } }

bean2.xml 要引入事務的操作的約束!
一般以后引入四個約束 beans context aop tx 示例見bean2.xml
可以測試無事務操作時可以正確執行

聲明式的事務管理:
  xml實現:
(使用的是aop的思想)(jdbc的源碼查看dataSourceTransactionManager)

聲明式事務管理建立在AOP之上的。其本質是對方法前后進行攔截,然后在目標方法開始之前創建或者加入一個事務,在執行完目標方法之后根據執行情況提交或者回滾事務。聲明式事務最大的優點就是不需要通過編程的方式管理事務,這樣就不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明(或通過基於@Transactional注解的方式),便可以將事務規則應用到業務邏輯中。——引自網友博客。

bean2.xml

<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.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">

    <!-- 配置c3p0連接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 進行屬性注入 -->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    
    <!-- 配置service對象 -->
    <bean id="acountService" class="cn.acount.AcountService">
        <!-- service中注入dao -->
        <property name="dao" ref="dao"></property>
    </bean>
    
    <!-- 配置dao對象 -->
    <bean id="dao" class="cn.acount.AcountDao">
        <!-- dao中注入模板 -->
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
    
    <!-- 創建模板對象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 模板中注入dataSource -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 事務的配置實現 -->
    <!-- 1.配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入dataSource -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 2.配置事務增強 ,需要指定事務管理器-->
    <tx:advice id="txadvice" transaction-manager="transactionManager">
        <!-- 做事務操作 -->
        <tx:attributes>
            <!-- 設置進行事務操作的方法匹配規則 -->
            <tx:method name="acount*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!-- 3.配置切面 -->
    <aop:config>
        <!-- 3.1切入點 -->
        <aop:pointcut expression="execution(* cn.acount.AcountService.*(...))" id="pointcut1"/>
        <!-- 3.2切面 -->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
    </aop:config>
</beans>

  進行一個簡單的測試:

package cn.acount; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test01 { @Test public void test(){ ApplicationContext context = 
                new ClassPathXmlApplicationContext("bean2.xml"); AcountService service = (AcountService) context.getBean("acountService"); service.acountMoney(); } }

 

  注解實現:
  配置事務管理器(事務管理器本身也是一個bean),它管的是數據源(需要注入數據源)
  配置開啟注解的操作(啟動事務注解)
  在要使用事務的方法所在的類上添加注解@Transactional(類上,方法上)

  如果不在service上加@Transactional注解,將會報transactional只為可讀的500錯誤!
  會自動找到@注解后對類里的所有方法進行事務操作(自定義的異常只要搞構造器就可以了!

此時的配置文件如下:

bean4.xml:

<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.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"> 
    
    <!-- 配置c3p0連接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 進行屬性注入 -->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <!-- 配置事務管理器-->
    <!-- 1.配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入dataSource -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 開啟事務的注解 ,指定事務管理器-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    <!-- 配置service對象 -->
    <bean id="acountService" class="cn.acount.AcountService">
        <!-- service中注入dao -->
        <property name="dao" ref="dao"></property>
    </bean>
    
    <!-- 配置dao對象 -->
    <bean id="dao" class="cn.acount.AcountDao">
        <!-- dao中注入模板 -->
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
    
    <!-- 創建模板對象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 模板中注入dataSource -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>

 

在類上加注解:完整的類信息見xml配置實現

@Transactional public class AcountService {

   使用注解形式開發時,可以使用注解的形式:

    //添加事務注解 //1.使用 propagation 指定事務的傳播行為, 即當前的事務方法被另外一個事務方法調用時 //如何使用事務, 默認取值為 REQUIRED, 即使用調用方法的事務 //REQUIRES_NEW: 事務自己的事務, 調用的事務方法的事務被掛起. //2.使用 isolation 指定事務的隔離級別, 最常用的取值為 READ_COMMITTED //3.默認情況下 Spring 的聲明式事務對所有的運行時異常進行回滾. 也可以通過對應的 //屬性進行設置. 通常情況下去默認值即可. //4.使用 readOnly 指定事務是否為只讀. 表示這個事務只讀取數據但不更新數據, //這樣可以幫助數據庫引擎優化事務. 若真的事一個只讀取數據庫值的方法, 應設置 readOnly=true //5.使用 timeout 指定強制回滾之前事務可以占用的時間. // @Transactional(propagation=Propagation.REQUIRES_NEW, // isolation=Isolation.READ_COMMITTED, // noRollbackFor={UserAccountException.class})
    @Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED, readOnly=false, timeout=3) @Override public void purchase(String username, String isbn) { try { Thread.sleep(5000); } catch (InterruptedException e) {} //1. 獲取書的單價
        int price = bookShopDao.findBookPriceByIsbn(isbn); //2. 更新數的庫存
 bookShopDao.updateBookStock(isbn); //3. 更新用戶余額
 bookShopDao.updateUserAccount(username, price); } }

 


免責聲明!

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



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