閱讀下面實驗之前:請先閱讀官方的分布式事務支持內容:https://shardingsphere.apache.org/document/current/cn/features/transaction/
經過試驗,單服務跨數據源,使用shardingJdbc的事務,同普通jdbc時的做法一樣。實驗版本 shrading-jdbc-spring-boot-starter ver.3.1.0
1)啟動類 (前提:pom引入spring-boot-starter-jdbc或者引入spring-boot-starter-data-jpa依賴,啟動類使用注解開啟事務管理器@EnableTransactionManagement):
package com.chong.mcspcshardingdbtable; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.ComponentScan; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class}) @EnableDiscoveryClient @EnableTransactionManagement @ComponentScan(basePackages = {"com.chong.common","com.chong.mcspcshardingdbtable"}) public class McSpcShardingDbTableApplication { public static void main(String[] args) { SpringApplication.run(McSpcShardingDbTableApplication.class, args); } }
2)service方法引入事務注解
@Transactional public List<BizMember> saveMembersToMutliDbs(String name,String name2) { BizMember member1 = newMember(); member1.setFullName(name); member1.setGender(1); // 存放到mcspcsharding1庫 BizMember member2 = newMember(); member2.setFullName(name2); member2.setGender(2);// 存放到mcspcsharding0庫 List<BizMember> memberList = new ArrayList<>(); memberList.add(memberRepository.save(member1)); memberList.add(member2 = memberRepository.save(member2)); return memberList; }
3)實驗之數據庫構成:mcspcsharding0放置gender=2的數據;mcspcsharding1放置gender=1的數據;
4)實驗步驟:通過postman,投放數據,name1符合要求,name2不符合要求(數據超長)。Rest格式為 POST: url/{name1}/{name2}
5)實驗結果:
A.可以看出第一條語句插入name1的會員執行通過,第二條語句插入name2的語句執行失敗,失敗原因為name2的參數內容長度超出數據庫列長的限制。
B.數據庫中確認實際入庫記錄,name1和name2的數據都沒有插入到數據庫中。證明通過簡單的兩個事物注解,實現了跨數據源的事務控制。
todo:兩個庫的事務commit和rollback機制在shardingjdbc里如何實現的,需要抽空研究。
console內容:
2020-02-29 19:10:47.962 INFO 24132 --- [io-9060-exec-10] ShardingSphere-SQL : Rule Type: sharding 2020-02-29 19:10:47.966 INFO 24132 --- [io-9060-exec-10] ShardingSphere-SQL : Logic SQL: insert into mc_member (age, create_time, create_user, full_name, gender, is_delete, update_time, update_user, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?) 2020-02-29 19:10:47.971 INFO 24132 --- [io-9060-exec-10] ShardingSphere-SQL : SQLStatement: InsertStatement(super=DMLStatement(super=io.shardingsphere.core.parsing.parser.sql.dml.insert.InsertStatement@68a542c3), columns=[Column(name=age, tableName=mc_member), Column(name=create_time, tableName=mc_member), Column(name=create_user, tableName=mc_member), Column(name=full_name, tableName=mc_member), Column(name=gender, tableName=mc_member), Column(name=is_delete, tableName=mc_member), Column(name=update_time, tableName=mc_member), Column(name=update_user, tableName=mc_member), Column(name=id, tableName=mc_member)], generatedKeyConditions=[], insertValues=InsertValues(insertValues=[InsertValue(type=VALUES, expression=(?, ?, ?, ?, ?, ?, ?, ?, ?), parametersCount=9)]), columnsListLastPosition=112, generateKeyColumnIndex=-1, insertValuesListLastPosition=148) 2020-02-29 19:10:47.976 INFO 24132 --- [io-9060-exec-10] ShardingSphere-SQL : Actual SQL: ms1 ::: insert into mc_member0 (age, create_time, create_user, full_name, gender, is_delete, update_time, update_user, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?) ::: [[45, 2020-02-29 19:09:41.749, 245, name12, 1, 0, null, null, 4041594688888832]] Hibernate: insert into mc_member (age, create_time, create_user, full_name, gender, is_delete, update_time, update_user, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?) 2020-02-29 19:10:47.999 INFO 24132 --- [io-9060-exec-10] ShardingSphere-SQL : Rule Type: sharding 2020-02-29 19:10:48.001 INFO 24132 --- [io-9060-exec-10] ShardingSphere-SQL : Logic SQL: insert into mc_member (age, create_time, create_user, full_name, gender, is_delete, update_time, update_user, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?) 2020-02-29 19:10:48.002 INFO 24132 --- [io-9060-exec-10] ShardingSphere-SQL : SQLStatement: InsertStatement(super=DMLStatement(super=io.shardingsphere.core.parsing.parser.sql.dml.insert.InsertStatement@68a542c3), columns=[Column(name=age, tableName=mc_member), Column(name=create_time, tableName=mc_member), Column(name=create_user, tableName=mc_member), Column(name=full_name, tableName=mc_member), Column(name=gender, tableName=mc_member), Column(name=is_delete, tableName=mc_member), Column(name=update_time, tableName=mc_member), Column(name=update_user, tableName=mc_member), Column(name=id, tableName=mc_member)], generatedKeyConditions=[], insertValues=InsertValues(insertValues=[InsertValue(type=VALUES, expression=(?, ?, ?, ?, ?, ?, ?, ?, ?), parametersCount=9)]), columnsListLastPosition=112, generateKeyColumnIndex=-1, insertValuesListLastPosition=148) 2020-02-29 19:10:48.002 INFO 24132 --- [io-9060-exec-10] ShardingSphere-SQL : Actual SQL: ms0 ::: insert into mc_member0 (age, create_time, create_user, full_name, gender, is_delete, update_time, update_user, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?) ::: [[73, 2020-02-29 19:09:41.75, 873, name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1name1, 2, 0, null, null, 4041594693083136]] 2020-02-29 19:10:48.020 WARN 24132 --- [io-9060-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1406, SQLState: 22001 2020-02-29 19:10:48.020 ERROR 24132 --- [io-9060-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : Data truncation: Data too long for column 'full_name' at row 1 2020-02-29 19:10:48.043 ERROR 24132 --- [io-9060-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.DataException: could not execute statement] with root cause com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'full_name' at row 1 at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:104) ~[mysql-connector-java-8.0.19.jar:8.0.19] at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) ~[mysql-connector-java-8.0.19.jar:8.0.19] at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092) ~[mysql-connector-java-8.0.19.jar:8.0.19] at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040) ~[mysql-connector-java-8.0.19.jar:8.0.19]