Foxnic-SQL (11) —— DAO 特性 : 事務管理
概述
事務管理是任何一個數(shù)據層工具所必須的,F(xiàn)oxnic-SQL 既然是基于 Spring JDBC 的自然默認就支持 @Transactional 注解,另外 Foxnic-SQL 的 DAO 對象還支持手動事務。
本文中的示例代碼均可在 https://gitee.com/LeeFJ/foxnic-samples 項目中找到。
手動事務
手動事務通過 DAO 對象的 beginTransaction() 方法、commit() 方法、rollback() 方法完成,下面是一個手動事務的例子:
public class DAO_ManualTransactionDemo {
? ? public static void main(String[] args) {
? ? ? ? demo1(true);
? ? ? ? demo1(false);
? ? }
? ? /**
* 1、查詢不分頁記錄集
* */
? ? public static void demo1(boolean exp) {
? ? ? ? // 通過 DBInstance 拿到 DAO 對象
? ? ? ? DAO dao=DBInstance.DEFAULT.dao();
? ? ? ? String id = null;
? ? ? ? try {
? ? ? ? ? ? // 啟動事務
? ? ? ? ? ? dao.beginTransaction();
? ? ? ? ? ? System.out.println("開始事務");
? ? ? ? ? ? // 插入數(shù)據
? ? ? ? ? ? id=insertAddress(dao,"13777-"+exp);
? ? ? ? ? ? if(exp) {
? ? ? ? ? ? ? ? throw new RuntimeException("模擬異常");
? ? ? ? ? ? }
? ? ? ? ? ? // 提交
? ? ? ? ? ? dao.commit();
? ? ? ? ? ? System.out.println("提交事務");
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? // 回滾
? ? ? ? ? ? dao.rollback();
? ? ? ? ? ? System.out.println("回滾事務");
? ? ? ? }
? ? ? ? Rcd address=queryAddress(dao,id);
? ? ? ? if(address==null) {
? ? ? ? ? ? System.out.println("數(shù)據未插入");
? ? ? ? } else {
? ? ? ? ? ? System.out.println("數(shù)據已插入");
? ? ? ? }
? ? }
? ? /**
* 插入數(shù)據
* */
? ? public static String insertAddress(DAO dao,String phone) {
? ? ? ? // 創(chuàng)建語句對象
? ? ? ? Insert insert=new Insert("example_address");
? ? ? ? String id= IDGenerator.getSnowflakeIdString();
? ? ? ? // 設置值
? ? ? ? insert.set("id",id)
? ? ? ? ? ? .set("name","leefj")
? ? ? ? ? ? // 如果是 null 則不連入SQL語句
? ? ? ? ? ? .setIf("phone_number",phone)
? ? ? ? ? ? .set("address","寧波")
? ? ? ? ? ? .set("region_type","國內")
? ? ? ? ? ? .set("create_time",new Date())
? ? ? ? ? ? // 設置數(shù)據庫表達式
? ? ? ? ? ? .setExpr("update_time","now()");
? ? ? ? // 輸出語句
? ? ? ? System.out.println(insert.getSQL());
? ? ? ? // 執(zhí)行語句
? ? ? ? Integer suc=dao.execute(insert);
? ? ? ? // 如果執(zhí)行成功,返回ID,否則返回 null
? ? ? ? if(suc==1) {
? ? ? ? ? ? return id;
? ? ? ? } else {
? ? ? ? ? ? return null;
? ? ? ? }
? ? }
? ? /**
* 查詢
* */
? ? public static Rcd queryAddress(DAO dao,String id) {
? ? ? ? // 創(chuàng)建語句對象
? ? ? ? Select select=new Select("example_address");
? ? ? ? // 設置值
? ? ? ? select.where().and("id=?",id);
? ? ? ? // 輸出語句
? ? ? ? System.out.println(select.getSQL());
? ? ? ? // 執(zhí)行語句
? ? ? ? Rcd address=dao.queryRecord(select);
? ? ? ? // 如果執(zhí)行成功,返回記錄對象,否則返回 null
? ? ? ? return address;
? ? }
}
自動事務
自動事務的前提是被注解 @Transactional 的對象需要是 Spring 容器管理的 Bean。所以自動事務通常會在 Web 應用中使用。自動事務需要首先定義數(shù)據源和事務管理器,并將兩者綁定,如下代碼所示:
@Configuration
? ? public class DatasourceConfig {
? ? ? ? public static final String PRIMARY_DATASOURCE_CONFIG_KEY = "spring.datasource.druid.primary";
? ? ? ? public static final String PRIMARY_DATA_SOURCE_NAME = "primaryDataSource";
? ? ? ? @Bean(name = PRIMARY_DATA_SOURCE_NAME)
? ? ? ? @ConfigurationProperties(PRIMARY_DATASOURCE_CONFIG_KEY)
? ? ? ? public DruidDataSource primaryDataSource() {
? ? ? ? ? ? return DruidDataSourceBuilder.create().build();
? ? ? ? }
? ? ? ? @Bean
? ? ? ? @Primary
? ? ? ? public DataSourceTransactionManager primaryTransactionManager(
? ? ? ? ? ? @Qualifier(PRIMARY_DATA_SOURCE_NAME) DataSource dataSource) {
? ? ? ? ? ? return new DataSourceTransactionManager(dataSource);
? ? ? ? }
? ? }
@Transactional注解
如果需要更高級的事務控制,則使用@Transactional注解,@Transactional 注解雖然方便地實現(xiàn)事務托管,但是還是有很多地方需要注意的,下面我們來了解一下在使用@Transactional注解時需要注意的點。
1、多數(shù)據源時需指定事務管理器名稱;
2、Spring事務是通過ThreadLocal類來實現(xiàn),所以只有主線程有事務管理,一個線程一個事務。
3、@Transactiona 注解需要事務管理器支持,若無事務管理器支持,則不生效。
4、@Transactional 注解可用于接口定義、接口方法、類定義、類public方法四個位置,非public方法事務不生效。
5、Spring事務控制是基于AOP的,請明確代理類型。proxy-target-class=true時,使用cglib的基于類的代理;proxy-target-class=false時,使用JDK的基于接口的代理。基于上述情況,@Transactional 注解建議放到類定義或類方法上。
6、如果類定義中無 @Transactional 注解,它的方法A無 @Transactional 注解,但方法B有 @Transactional 注解,此時若在同一個類中,由A調用B,則B上的事務無效。如果類定義中有@Transactional注解,則它的方法,無論有無 @Transactional 注解,事務均有效??傊?,如果要使事務有效,調用時進入類的第一個類方法必須有 @Transactional 注解。
7、Spring 使用聲明式事務處理,默認情況下, 如果被注解的數(shù)據庫操作方法中發(fā)生了 unchecked 異常(編譯器不檢查的異常,如 RuntimeException),所有的數(shù)據庫操作將 rollback;如果發(fā)生的異常是 checked 異常(編譯器檢查,需要用try cathch 捕獲處理的異常,如 Exception),默認情況下數(shù) 據庫操作還是會提交的。當然也可在 @Transactional 注解中指定回滾的異常類型。
下面是使用 @Transactional? 事務托管的幾個示例:
@Transactional(AppDAO.TRANSACTION_MANAGER)
public String te1(String act) throws Exception
{
if(act==null) act="none";
dao.execute("update trans set name=?? where code='119'",act+":"+System.currentTimeMillis());
if(act.equals("checked")) {
//事務不回滾
throw new Exception("異常");
}
if(act.equals("unchecked")) {
//事務回滾
throw new RuntimeException("異常");
}
return "OK";
}
變更默認的回滾異常,指定回滾或不回滾的異常類型:
@Transactional(transactionManager=AppDAO.TRANSACTION_MANAGER,rollbackFor= {Exception.class},noRollbackFor= {RuntimeException.class})
public String te2(String act) throws Exception
{
if(act==null) act="none";
dao.execute("update trans set name=?? where code='119'",act+":"+System.currentTimeMillis());
if(act.equals("checked")) {
//事務回滾
throw new Exception("異常");
}
if(act.equals("unchecked")) {
//事務不回滾
throw new RuntimeException("異常");
}
return "OK";
}
事務傳播
Spring 的事務的傳播行為,默認值為 Propagation.REQUIRED。 可選的值有:
1、Propagation.REQUIRED:如果當前存在事務,則加入該事務,如果當前不存在事務,則創(chuàng)建一個新的事務。
2、Propagation.SUPPORTS:如果當前存在事務,則加入該事務;如果當前不存在事務,則以非事務的方式繼續(xù)運行。
3、Propagation.MANDATORY:如果當前存在事務,則加入該事務;如果當前不存在事務,則拋出異常。
4、Propagation.REQUIRES_NEW:重新創(chuàng)建一個新的事務,如果當前存在事務,暫停當前的事務。
5、Propagation.NOT_SUPPORTED:以非事務的方式運行,如果當前存在事務,暫停當前的事務。
6、Propagation.NEVER:以非事務的方式運行,如果當前存在事務,則拋出異常。
7、Propagation.NESTED:和 Propagation.REQUIRED 效果一樣。
事務隔離
isolation 屬性,事務的隔離級別,默認值為 Isolation.DEFAULT??蛇x的值有:
1、Isolation.DEFAULT:使用底層數(shù)據庫默認的隔離級別。MYSQL:默認為 REPEATABLE_READ 級別;SQLSERVER:默認為 READ_COMMITTED 級別;Oracle:默認為 READ_COMMITTED 級別。
2、Isolation.READ_UNCOMMITTED
3、Isolation.READ_COMMITTED
4、Isolation.REPEATABLE_READ
5、Isolation.SERIALIZABLE
其它參數(shù)
1、timeout 屬性:事務的超時時間,默認值為-1。如果超過該時間限制但事務還沒有完成,則自動回滾事務。
2、readOnly 屬性:指定事務是否為只讀事務,默認值為 false;為了忽略那些不需要事務的方法,比如讀取數(shù)據,可以設置 read-only 為 true。
小結
本節(jié)主要介紹了在 Foxni-SQL 中的事務管理,包括了手動事務個 Spring 托管的自動事務。在使用自動事務時要注意本文中提到的針對? @Transactional 注解使用的注意事項。
相關項目
https://gitee.com/LeeFJ/foxnic
https://gitee.com/LeeFJ/foxnic-web
https://gitee.com/LeeFJ/foxnic-samples