范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

聊一聊Spring中的Transaction基本实现

  聊一聊Spring中的 Transaction基本实现
  我们知道加一个 org.springframework.transaction.annotation.Transactional   注解便可以让改方法实现事务管理(提交/回滚), 但是我们知道一个如何用编码的方式实现事务如何回滚的 . 抛开动态代理 , 其实事务就是动态代理实现, 但是不是我们的重点 , 我们要讲讲他为啥只支持单个数据源 还有不支持 异步操作(这里的意思是在事务里开启一个新线程执行业务)前言
  一般操作都是下面这样子 , 基本流程 // 获取连接 Connection connection = dataSource1.getConnection(); try {     // 设置事务隔离等级     connection.setTransactionIsolation(3);     // 设置自动提交为false     connection.setAutoCommit(false);      // 业务     PreparedStatement statement = connection.prepareStatement();     statement.execute();      // 成功提交     connection.commit(); } catch (Exception e) {         // 异常rollback     connection.rollback(); } finally {     // 设置为true     connection.setAutoCommit(true);     // 关闭     connection.close(); }
  所以Spring帮助我们做的就是这个, 那么它一定也是这么实现的 .
  如何启动事务呢 ,
  首先需要加入依赖      org.springframework     spring-tx     5.0.8.RELEASE 
  SpringBoot 可以使用这个 org.springframework.transaction.annotation.EnableTransactionManagement   ,对于XML配置可以去看看这个类, 他会教你咋配置 .
  方法控制是依靠 @Transactional(transactionManager ="TransactionManager")   ,
  然后我们需要自己自定义实现一个 org.springframework.transaction.PlatformTransactionManager   Bean , 告诉spring事务处理的使用哪个
  那么为啥加了个注解就会自动给你管理事务了呢 , 他难道不是这么做的吗.
  其实看 org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration   这个地方@Configuration // 前提你只有一个数据源 @ConditionalOnSingleCandidate(DataSource.class) static class DataSourceTransactionManagerConfiguration {     ...........     // 这里PlatformTransactionManager前提你不实现     @Bean     @ConditionalOnMissingBean(PlatformTransactionManager.class)     public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {         DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);         return transactionManager;     } }
  在你单数据源的情况下, 同时自动注入情况下, 他会默认给你生成一个 DataSourceTransactionManager
  所以默认情况下, 就是走这个, 现在我们绝地不看这个 . 我们要自己实现 . 正文"
  我们的问题 . @Configuration public class DataConfig {      @Bean("datasource1")     public DataSource dataSource() {         try {             Class.forName("com.mysql.jdbc.Driver");         } catch (ClassNotFoundException e) {             e.printStackTrace();         }         MysqlDataSource dataSource = new MysqlDataSource();         dataSource.setURL("jdbc:mysql://localhost:3306/jpa?useSSL=false");         dataSource.setUser("root");         dataSource.setPassword("123456");         return dataSource;     }     // 还有一个 datasource2     @Bean(name = "TransactionManager1")     public DataSourceTransactionManager clusterTransactionManager(@Qualifier("datasource1") DataSource dataSource) {         return new DataSourceTransactionManager(dataSource);     }     // 还有一个 TransactionManager2,地方有限 }
  我们定义俩数据源, 其中就需要俩 DataSourceTransactionManager
  那么写我们的service @Service public class TestService {     @Autowired     @Qualifier("datasource1")     private DataSource dataSource1;      @Transactional     public void test() throws SQLException {         Connection connection1 = dataSource1.getConnection();         Statement statement1 = connection1.createStatement();         int i = statement1.executeUpdate("INSERT INTO go_user (`name`,`password`) VALUES ("name12345","p5")");         System.out.println("成功 : " + i);         int x = 1 / 0;         // 连接二也是如此 . 懒得写 , 我测试的时候写的俩数据源     } }
  这样子启动绝对会GG , 因为你没指定有哪个 TransactionManager   .
  那么我们怎么做, @Transactional(transactionManager = "TransactionManager2")
  但是事务处理的时候 org.springframework.jdbc.datasource.DataSourceTransactionManager#doRollback  @Override protected void doRollback(DefaultTransactionStatus status) {     DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();     Connection con = txObject.getConnectionHolder().getConnection();     try {         con.rollback();     }     catch (SQLException ex) {     } }
  他有一个 Connection   , 那么不和我们的connection一样 , 那么绝对回滚不了哇. 因为你不是一个连接, 所以根本题绝对提交成功了 , 那么为啥Mybatis  可以呢 . 所以借鉴一下,
  我们看MyBatis的实现  org.mybatis.spring.transaction.SpringManagedTransaction   在这里, 这里缩进不了了 , 他的tab是俩空格, 我是四个, 哎 . 就这么看吧  @Override   public Connection getConnection() throws SQLException {       // 连接为null     if (this.connection == null) {         // 打开一个       openConnection();     }     return this.connection;   }   private void openConnection() throws SQLException {      // 获取Connection , 原来如此 这么获取     this.connection = DataSourceUtils.getConnection(this.dataSource);     this.autoCommit = this.connection.getAutoCommit();     this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);   }
  所以就是在获取这里 DataSourceUtils   ->org.springframework.jdbc.datasource.DataSourceUtils#getConnection  public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {     try {         return doGetConnection(dataSource);     }     catch (SQLException ex) {         ///     } }
  doGetConnection(dataSource)  ->org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection  public static Connection doGetConnection(DataSource dataSource) throws SQLException {     // 获取一个 ConnectionHolder 持有对象 . 奥原来这样子 .      // 通过 TransactionSynchronizationManager     ConnectionHolder  conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);     if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {         conHolder.requested();         if (!conHolder.hasConnection()) {             conHolder.setConnection(fetchConnection(dataSource));         }         return conHolder.getConnection();     }     /// ....  }
  TransactionSynchronizationManager.getResource(dataSource);   -> org.springframework.transaction.support.TransactionSynchronizationManager#getResource  @Nullable public static Object getResource(Object key) {     // key      Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);     // 获取值     Object value = doGetResource(actualKey);     //...     return value; }
  doGetResource(actualKey);  ->org.springframework.transaction.support.TransactionSynchronizationManager#doGetResource  @Nullable private static Object doGetResource(Object actualKey) {     // 获取map     Map map = resources.get();     // map拿value     Object value = map.get(actualKey);        // ...     return value; }
  其实 resources   就是啥, 就是一个 ThreadLocal 维护的一个线程对象,private static final ThreadLocal> resources =         new NamedThreadLocal<>("Transactional resources");
  所以这就是为啥说事务不支持异步的原因了, 只能一个线程执行一个事务 , 不能俩线程执行 , 比如说这种,绝对不行. new Thread(() -> mapper.findByName("tom")).start();
  其实到这里我们就拿到了 ConnectionHolder  了 ,org.springframework.jdbc.datasource.ConnectionHolder  其实就是一个连接持有者, 一层封装罢了 , 多了一些额外信息.
  那么到这里他是如何加入进去的呢, 那就是
  org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin   这个方法了@Override protected void doBegin(Object transaction, TransactionDefinition definition) {     // 无所谓..     DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;     Connection con = null;     try {         if (!txObject.hasConnectionHolder() ||                 txObject.getConnectionHolder().isSynchronizedWithTransaction()) {             // 没有就newCon             Connection newCon = obtainDataSource().getConnection();             txObject.setConnectionHolder(new ConnectionHolder(newCon), true);         }         txObject.getConnectionHolder().setSynchronizedWithTransaction(true);         // 获取连接         con = txObject.getConnectionHolder().getConnection();          // 获取事务隔离等级         Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);         txObject.setPreviousIsolationLevel(previousIsolationLevel);         // 自动提交关闭         if (con.getAutoCommit()) {             txObject.setMustRestoreAutoCommit(true);             con.setAutoCommit(false);         }         // ... 这里就是保存对象了 .           if (txObject.isNewConnectionHolder()) {             //  这里就是添加进去             TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());         }     } }
  org.springframework.transaction.support.TransactionSynchronizationManager#bindResource  public static void bindResource(Object key, Object value) throws IllegalStateException {     // key     Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);     Map map = resources.get();     if (map == null) {         map = new HashMap<>();         resources.set(map);     }     // 添加进去     Object oldValue = map.put(actualKey, value); }
  所以前前后后就是这个, 所以懂了吗 // 通过 DataSourceUtils.getConnection(dataSource1); 获取当前线程的连接 Connection connection2 = DataSourceUtils.getConnection(dataSource1); // 执行 ... Statement statement1 = connection1.createStatement(); int i = statement1.executeUpdate("INSERT INTO go_user (`name`,`password`) VALUES ("name12345","p5")");
  所以这就是 transaction 的内容 , 总结
  我们观察源码 发现 Transaction 不支持异步操作 , 不支持单任务(单个请求)多数据源, 所以不能保证多数据源的事务相关问题 ,
  因此下一期我讲解多数据源 (分库分表其实也是这样子) , 或者 微服务下多数据源问题 .

数字化转型应重点构筑的核心能力解析数字化转型应重点构筑的几大核心能力1以客户为中心的组织能力体系1)组织结构从以产品为中心向以客户为中心转变传统模式下,零售企业以我为中心,不同产品的营销服务通常自成体系。数字经济下激光雷达和视觉算法哪个更适合自动驾驶?自动驾驶注定会成为未来改变世界的技术不过在这个技术蓬勃发展的当下却有两个旗帜鲜明的技术流派一派支持只用视觉算法实现L4L5级自动驾驶另一派认为视觉算法安全冗余不够完全可靠的自动驾驶AMD放大招R93950X不到六千眼看着2019年还剩不到两个月就要结束了,按理说今年的电脑处理器市场也该尘埃落定,但AMD方面似乎并不这么想。11月7日AMD方面正式公布了锐龙93950X(以下简称R93950X情怀有点贵摩托罗拉折叠翻盖手机发布北京时间11月14日,摩托罗拉在洛杉矶发布了Razr2019系列折叠屏翻盖手机,这部手机从预热到正式发布可谓是赚足了眼球,毕竟把折叠屏手机做成翻盖样式看上去比三星以及华为的折叠屏手二手备用手机水太深?明白这些不被坑随着社会发展越来越快,很多小伙伴平时都使用着不止一张卡,但除去主力手机外,备用机型基本就是接打个电话,花太多钱又不合适,毕竟钱也不是大风刮来的。于是很多小伙伴都把目光转向了二手手机夹缝中的AMD,能凭借锐龙三代翻身吗?前段时间AMD发布了旗下最新的锐龙系列处理器,这一代锐龙处理器依然走高性价比路线,虽然三代锐龙处理器还没有正式发货,但却已经在民间激起了惊涛骇浪,因为这一代的锐龙处理器的性价比实在密码管理应用程序Dashlane视觉形象升级Dashlane是一款移动和桌面应用程序,创办于2009年,用户可以通过该应用管理自己的互联网上的各种帐号和密码,自动填写登陆表单,实现简单安全的快捷登录。最近,他们公布了由Pen公路客运运营商ALSA视觉形象升级ALSA创办于1923年,是西班牙公路客运领域的领先运营商,作为一个整体运营商,它能够满足市民的不同交通需求,提供广泛的区域国家国际城市长途汽车租赁和旅游服务。此外,还专门从事公交败光120亿,坑了9000名员工,80后富二代是如何搞垮山西最大民企2003年1月22日上午,山西闻喜县前企业家冯引亮,带上了两把枪,决定亲自上门寻找李海仓,做最后的摊牌。自从冯引亮回来家乡之后,李海仓就一直避而不见。冯引亮想将自己纸厂的那块地,以30岁,喜茶创始人身家150亿万千少女追捧的喜茶又又双叒叕融资了!近期,喜茶刚刚交割完毕新一轮5亿美元的融资,投资方包括黑蚁资本腾讯红杉资本高瓴资本淡马锡LCatterton和日初资本。而喜茶的估值在这一轮融资佛媛生意坐禅抄经穿Dior,佛门炫富也能火?在冲浪第一线的你,不知道有没有发现,小红书抖音上的网红开始争当佛媛了。佛媛目前没有明确的含义,泛指以抄经拜佛品茶为日常的生活方式,同时具有美貌和财富的新名媛,是礼佛和名媛的结合体。
苹果华为领衔,年底还值得入手的三款旧旗舰,保值率极高随着年底又一波新机潮来袭,今年发布的新机可是太多了!而这时对于很多旧机,降价成了必然的出路,要不就是参与优惠活动,要不就是二手大量出现但今天小编想说说有这么几款机型,发售一年了,市为什么有人宁愿溢价买华为,也不考虑性价比高还有现货的小米?性价比需求价格。记住这个公式,不要被某些厂商带偏了,便宜就是性价比高,贵的就是性价比低么?怎么理解这个公式?同样的价格,能满足用户的需求越多,那性价比也就越高。能满足用户的需求,价续航里程接近腰斩!潮水退去之后就知道谁在裸泳!新能源车冬季能跑多远?续航里程会腰斩嘛?我相信续航是广大新能源车消费者十分重视的问题,尤其是深处我国北部地区的车主们。对他们来说,续航里程折扣的越少,低气温下跑的越久,日常出行患上互联网大公司深陷裁员潮,是行业问题还是未来趋势?1。互联网发展到当下阶段,流量红利已经消失,获客成本越来越高,但是新增流量不足,增长乏力。2。绝大多少互联网的创新更多的是业务场景的创新,把传统的线下业务搬到线上,没有开拓新的市场对于联想杨元庆此时以个人名义捐款的事你怎么看,是想收买人心吗?再怎么捐也收不回人心了,因为这些厚此薄彼的所谓的企业家,在我们老百姓眼里也一文不值。杨解释如何贷款几十亿买联想股份才是正解聪明人。地位太高了,要有自觉,要有大爱。钱太多花不完的,共新品荣耀x30性能怎么样?感谢邀请新品荣耀x30性能怎么样?从客观角度来说和同价位的手机配置不成正比,虽然荣耀赵明确实说过我们能把高通778G处理器的性能发挥到极致,甚至媲美高通888。但是我们要知道的是受司柳之争的结果会是什么样?司柳之争的结果怎样,我们暂且不说,但从这场风波的持续发酵,可以明显地看出已经形成了鲜明的两大阵线即以支持司马南为一方的广大的劳动群众和以支持柳先生一方的既得利益集团和一些所谓精英代新手必备吸尘器飞利浦家电FC6409马上就要到年底了,家家又要开启大扫除模式了。而今吸尘器已经在家里的地位是非常高的立刻!成为了大扫除必备工具之一,但是现在市面上吸尘器的种类实在是太多了,还有一些有尘袋,有些没有,现真的卖不动了?骁龙888旗舰直降1000离场,5倍光变120W2亿镜头努比亚发展至今虽已沦为小众品牌,但它敢于创新的精神还是让不少用户对它保留着深刻的印象。还记得当初努比亚推出的极限屏占比新机很有影响力,但现在由于努比亚的名气没有华米OV的大,导致旗ViV0一NE逆天黑科技,全屏发声技术从2013年业内第一台2K屏手机Xplay3S,到2016年的HiFi旗舰机皇Xplay5旗舰版,再到世界首款量产的屏幕指纹手机X21UD版,以及2018年6月的黑科技旗舰vivo新能源汽车面临两条技术路线,追风口还是追趋势?今年中国新能源汽车市场爆发式增长。中国汽车工业协会的数据显示,110月,全国新能源汽车销量已超250万辆。多家新能源车企11月销量涨幅超过100,创下历史新高。有专家预计,前11个