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層處理,能夠最大化的保證數據的完整性。