spring對數據庫的操作、spring中事務管理的介紹與操作

jdbcTemplate的入門

  •   創建maven工程

 

     此處省略

 

  •   導入依賴
複製代碼
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
      <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>  
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.8</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

   <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
        
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.38</version>
    </dependency>
   <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.2.4.RELEASE</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.9</version>
    <scope>test</scope>
</dependency>
複製代碼

 

  •   配置文件中配置數據庫連接池

      

複製代碼
<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
        
        <!-- 配置spring提供的數據庫連接池 -->
        <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
            <property name="username" value="root"></property>
            <property name="password" value="123"></property>
        </bean> -->
        
        <!-- jdbcTemplate的配置 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
</beans>
複製代碼

 

  •   測試
複製代碼
 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext.xml")
 3 public class JdbcTemplateTest {    
 4     @Autowired
 5     private JdbcTemplate jdbcTemplate;
 6     
 7     //增刪改的測試
 8     @Test
 9     public void testName() throws Exception {
10         String sql = "insert into account values(null,?,?)";
11         jdbcTemplate.update(sql, "lisi",10000);
12     }
13 
14     //查詢簡單類型的測試
15     @Test
16     public void testName02() throws Exception {        
17         String sql = "select name from account where id=?";
18         String name = jdbcTemplate.queryForObject(sql, String.class,1);
19         System.out.println(name);
20     }
21     
22     //複雜類型的測試
23     @Test
24     public void testName03() throws Exception {
25         String sql = "select * from account where id=?";        
26         Account account = jdbcTemplate.queryForObject(sql, new MyRowMapper(),2);
27         System.out.println(account);        
28     }
29     
30     class MyRowMapper implements RowMapper<Account>{
31         @Override
32         public Account mapRow(ResultSet rs, int arg1) throws SQLException {
33             Account account = new Account();    //自己編寫的實體類        
34             account.setId(rs.getInt("id"));        //id,name,money爲實體類Account中的成員屬性
35             account.setName(rs.getString("name"));
36             account.setMoney(rs.getDouble("money"));            
37             return account;
38         }        
39     }    
40 }
複製代碼

 

 

 



 

 

spring配置文件中數據庫連接池的配置

 

  C3P0數據庫連接池的配置

      依賴的jar包

    

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>

 

      xml配置

複製代碼
        <!-- 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/spring"></property>
            <property name="user" value="root"></property>
            <property name="password" value="123"></property>
        </bean> 
複製代碼

 

 

  DBCP數據庫連接池的配置

      依賴的jar包

   

複製代碼
    <!-- dbcp數據庫連接池 -->
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>commons-pool</groupId>
        <artifactId>commons-pool</artifactId>
        <version>1.5.3</version>
    </dependency>
    
複製代碼

 

 

      xml配置

 

複製代碼
     <!-- dbcp數據庫連接池 -->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
            <property name="username" value="root"></property>
            <property name="password" value="123"></property>
        </bean> 
複製代碼

 

  Druid數據庫連接池的配置

      依賴的jar包

      

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.18</version>
    </dependency>

 

      xml配置

 

複製代碼
      <!-- druid數據庫連接池 -->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
            <property name="username" value="root"></property>
            <property name="password" value="123"></property>
        </bean>
複製代碼

 

  引入外部屬性配置文件來配置數據庫連接信息

 

     1. src/main/resources目錄下創建jdbc.properties

jdbc.driverClass=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/spring

jdbc.username=root

jdbc.password=root

     2. spring 的核心配置文件中加載我們的jdbc.properties配置文件

 

<context:property-placeholder location="classpath:db.properties"/>

 


           3. 改寫數據庫連接池的配置,通過佔位符來引用jdbc.properties屬性文件中的內容

複製代碼
     <!-- druid數據庫連接池 -->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${jdbc.driverClassName}"></property>
            <property name="url" value="${jdbc.url}"></property>
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
複製代碼

 

 



 

 

spring中事務的管理介紹

 

  事務的概念

事務主要是用來操作數據庫的,他的使用是用來保證數據的完整性和一致性。

事務就是一系列的操作,它們被當做一個單獨的工作單元。這些操作要麼全部成功,要麼全部失敗。

  事務的特性(ACID)

原子性(atomicity): 事務是一個原子操作,由一系列動作組成。事務的原子性確保動作要麼全部完成要麼完全不起作用。

一致性(consistency): 一旦所有事務動作完成,事務就被提交。數據和資源就處於一種滿足業務規則的一致性狀態中。

隔離性(isolation): 可能有許多事務會同時處理相同的數據,因此每個事物都應該與其他事務隔離開來,防止數據損壞。

持久性(durability): 一旦事務完成,無論發生什麼系統錯誤,它的結果都不應該受到影響。通常情況下,事務的結果被寫到持久化存儲器中。

 

  多個事務併發操作存在的問題

      讀的問題

1、髒讀:對於兩個事務T1,T2, T1 讀取了已經被 T2 更新但還沒有被提交的字段。 之後, 若 T2 回滾,T1讀取的內容就是臨時且無效的。【讀但未提交】

2、不可重複讀:對於兩個事務 T1, T2,T1 讀取了一個字段,然後 T2 更新了該字段.。之後, T1再次讀取同一個字段,值就不同了。【讀更讀】

3、幻讀:對於兩個事務 T1,T2, T1 從一個表中讀取了一個字段,然後 T2 在該表中插入了一些新的行。之後,如果 T1 再次讀取同一個表,就會多出幾行。【讀插讀】

      寫的問題

        丟失更新  :兩個事務同時寫一條記錄,後一個事務把前一個事務的數據覆蓋了,導致前一個事務的數據丟失。

 

  事務的隔離級別

      • 讀未提交(read uncommited)

  允許事務讀取其他事務未提交的更新,髒讀 、不可重複讀、幻讀都會出現。

 

      • 讀已提交(read commited)

  只允許事務讀取其他事務已經提交的變更。可以避免髒讀,但不可重複讀和幻讀問題仍然可能出現。

 

      • 可重複讀(repeatable read)

  確保一個事務可以多次從一個字段中讀取相同的值。在這個事務持續期間,禁止其他的事務對這個字段做更新操作。可以避免髒讀、不可重複讀,但是幻讀仍然可能發生。

 

      • 串行化(serialzable)

  確保一個事務可以多次從一個表中讀取相同的行。在這個事務持續期間,禁止其他事務對這張表進行插入、刪除、更新操作。所有的併發都被避免,但是效率低下。

 

 

  spring的平臺事務管理器

PlatformTransactionManager接口有一系列的實現類,用於不同的事務管理,其中最常用的類是【 HibernateTransactionManager】和【 DataSourceTransactionManager】。

HibernateTransactionManager用 Hibernate 框架存取數據庫。

DataSourceTransactionManager通過 JDBC 操作數據庫來管理事務。

它爲事務管理封裝了一組獨立於技術的方法。無論使用 Spring 的哪種事務管理策略(編程式或聲明式事務管理),事務管理器都是必須的

  spring中事務的定義

      •   事物的隔離級別
      •   事物的傳播行爲
      •   事物的超時信息
      •   事物是否只讀

 

 

  spring當中事務的狀態信息定義

  •   狀態是否有保存點
  •   事物是否完成
  •   是不是一個新的事物
  •   是否僅僅回滾

 

 

spring當中的事務執行過程

 

Spring當中通過TransactionDefinition來對事物進行定義,然後通過PlatformTransactionManager來對事物進行操作,並且將操作後的事物狀態,保存到TransactionStatus當中

 

 

 

  spring當中事務的傳播行爲

 

    事務傳播行爲的介紹

事務方法的互相調用時(當一個事務方法被另一個事務方法調用時)必須指定事務應該如何傳播。方法可能繼續在現有事務中運行, 也可能開啓一個新事務, 並在這個新的事務中運行。 事務的傳播行爲可以由傳播屬性指定。Propagation(傳播,擴展)默認值是required,即是如果當前存在事務,則不進行創建,只是利用當前事務,如果當前沒有事務,則是進行創建。

    舉例說明:Required傳播行爲


    傳播行爲的取值

 

 

 

 

 



 

 

Spring中事務的操作

 

Spring 既支持編程式事務管理,也支持聲明式的事務管理。

  編程式事務管理

  聲明式事務管理(xml配置方式和註解配置方式)

 

Spring中使用編程的方式進行事務管理

 

      spring配置文件中配置事務管理器和事務模版

複製代碼
     <!-- 配置事務的模版 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!-- 事務的模版 -->
        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager" ref="transactionManager"></property>
        </bean>
複製代碼

 

      接口和實現類

1 public interface AccountDao {
2     void moneyOut(int from, double money);
3     void moneyIn(int in, double money);
4 }
複製代碼
 1 @Repository
 2 public class AccountDaoImpl implements AccountDao {    
 3     @Autowired
 4     private JdbcTemplate jdbcTemplate;
 5 
 6     @Override
 7     public void moneyOut(int from, double money) {
 8         String sql = "update account set money = money - ? where id = ?";
 9         jdbcTemplate.update(sql, money,from);
10     }
11 
12     @Override
13     public void moneyIn(int in, double money) {
14         String sql = "update account set money = money + ? where id = ?";
15         jdbcTemplate.update(sql, money,in);
16     }
17 }
複製代碼

 

 

1 public interface AccountService {
2     public void transferMoney(int from,int in,double money);
3 }
複製代碼
 1 @Service
 2 public class AccountServiceImpl implements AccountService{    
 3     @Autowired
 4     private AccountDao accountDao;
 5     
 6     //注入事務模版
 7     @Autowired
 8     private TransactionTemplate transactionTemplate;
 9 
10     @Override
11     public void transferMoney(int from, int in, double money) {
12                 //編程式事務代碼
13         transactionTemplate.execute(new TransactionCallbackWithoutResult() {            
14             @Override
15             protected void doInTransactionWithoutResult(TransactionStatus arg0) {
16                 accountDao.moneyOut(from,money);                
17                 //拋出異常
18                 System.out.println(1/0);                
19                 accountDao.moneyIn(in,money);
20             }
21         });
22     }
23 }
複製代碼

 

      測試

複製代碼
 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext-tx.xml")
 3 public class TxTest {
 4     @Autowired
 5     private AccountService accountService;
 6     
 7     @Test
 8     public void testName() throws Exception {
 9         accountService.transferMoney(1, 2, 1000);
10     }
11 }
複製代碼

 

 

 

Spring中的聲明式事務管理(基於xml配置)

 

      開啓tx命名空間

 

      配置聲明式事務屬性及切入點

複製代碼
   <!-- 聲明事務管理:xml方式配置 -->
    <!-- 配置事務屬性:傳播行爲,隔離級別,事務回滾,只讀事務,超時結束 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 指定事務方法的事務屬性信息:如傳播行爲 -->
            <tx:method name="transfer*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 配置事務切入點,以及把事務切入點和事務屬性關聯起來 -->
    <aop:config>
        <aop:pointcut expression="execution(* *.transfer*(..))" id="pointCut"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
    </aop:config>
複製代碼

 

      測試

 

複製代碼
 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext-tx-xml.xml")
 3 public class XmlTransactionTest {
 4     @Autowired
 5     private AccountService accountService;
 6     
 7     @Test
 8     public void testName() throws Exception {
 9         accountService.transferMoney(1, 2, 1000);
10     }
11 }
複製代碼

 

Spring中的聲明式事務管理(基於註解的方式)

      開啓tx命名空間

 

      開啓註解掃描

 

    <!-- 註解方式的聲明式事務管理 -->
    <!-- 開啓聲明式事務管理的註解驅動 -->
    <tx:annotation-driven transaction-manager="transactionManager"/

 

      事務處理

      

複製代碼
@Service
@Transactional//注意加載service層,不要加在dao層
public class AccountServiceImpl implements AccountService{    
    @Autowired
    private AccountDao accountDao;
    
    @Override
    public void transferMoney(int from, int in, double money) {
        accountDao.moneyOut(from,money);        
        //拋出異常
        System.out.println(1/0);        
        accountDao.moneyIn(in,money);
    }
}
複製代碼

 

      測試

複製代碼
 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext-tx-annotation.xml")
 3 public class AnnotationTransactionTest {
 4     @Autowired
 5     private AccountService accountService;
 6     
 7     @Test
 8     public void testName() throws Exception {
 9         accountService.transferMoney(1, 2, 1000);
10     }
11 }
複製代碼

 

 

 

 Spring中的事務管理總結

  Spring 既支持編程式事務管理,也支持聲明式的事務管理

  

  編程式事務管理: 將事務管理代碼嵌入到業務方法中來控制事務的提交和回滾。在編程式管理事務時,必須在每個事務操作中包含額外的事務管理代碼,這樣的話,會引起業務代碼混亂。

  

  聲明式事務管理: 大多數情況下比編程式事務管理更好用。它將事務管理代碼從業務方法中分離出來,以聲明的方式來實現事務管理。事務管理作爲一種橫切關注點, 可以通過 AOP 方法模塊化。Spring 通過 Spring AOP 框架支持聲明式事務管理。建議使用這種方式。

  

    注意基於註解的聲明式事務管理,註解不要寫在dao層處理,應該將事務的處理提取到service層,因爲事務的回滾一般會牽涉到多個dao的使用,所以在service層處理,能夠最大化的保證數據的完整性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章