# learn-demo **Repository Path**: ClumsyBird/learn-demo ## Basic Information - **Project Name**: learn-demo - **Description**: 学习demo........................................ - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-09-28 - **Last Updated**: 2022-11-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 一、什么是资源管理器 什么是事务管理器 a、资源管理器(resourceManager):管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
这个具体来说就是指数据库
b、事务管理器(transactionManager):定义全局事务的范围:开始全局事务、提交或回滚全局事务。这个就是指全局事务,可以操作多个资源管理器,进行协调所有资源完成数据一致。
### 二、tomcat配置数据源,使用全局事务框架继承进行多数据源分布式事务 最终效果:
tomcat的context.xml配置
![输入图片说明](jta/demo1/image.png)
spring配置atomikos的全局事务
![输入图片说明](jta/demo1/image2.png)
jndi配置加载数据源
![输入图片说明](jta/demo1/image3.png)
![输入图片说明](jta/demo1/image4.png)
测试类
![输入图片说明](jta/demo1/image6.png)
![输入图片说明](jta/demo1/image7.png)
两个数据源在一个事务里,第一次插入id=6都插入进去;删除1库的id=6数据,再次执行,2库由于有id=6的数据报主键冲突,查看1库也进行回滚没有执行插入。
1、tomcat配置普通的数据源,并且集成jdbctemplate
(1)首先在tomcat的context.xml文件中配置:
``` ``` 说明:
a、此处使用的druid连接池,故而需要把druid的jar包以及mysql的jar包都放到tomcat的lib目录下,否则tomcat是找不到类报错的
b、在xml中 &符号要使用 & 转义字符进行拼接,否则会报错
c、是在节点下,弄错了不好使
d、链接参数要配置准确,不然报错也不太准确,可以先用jdbc试一下,再把链接参数放到这里
2、在项目中使用的这个配置
a 先测试tomcat的配置能否正常使用: ``` public void testJNDI2() throws Exception{ Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc_db1"); Connection conn = ds.getConnection(); System.out.println(conn); } ``` 这个代码运行后不报错就,正常获取conn就ok
b spring的配置文件中加入:
``` ``` 注:jndiName:第一步中所配置单独JNDI名称。
resourceRef:可以让我们指定jndiName时,省略前缀“java:comp/env/”。
坑:这里的JndiObjectFactoryBean不是这个bean的类型,这玩意儿的类型是tomcat的context.xml配置的工厂生成的datasource.... 然而idea中提示的这个配置的类型是JndiObjectFactoryBean,而且自动生成的代码也是这个类型,接着就报错了,故而ref这个bean的时候要写datasource的类型,写JndiObjectFactoryBean类型就报错了。
c 这玩意是datasource类型,那么就可以直接塞到jdbctemplate ``` ``` ``` DruidDataSource db1 = applicationContextHelper.popBean("db1", DruidDataSource.class); this.jdbcTemplate1 = new JdbcTemplate(db1); DruidDataSource db2 = applicationContextHelper.popBean("db2", DruidDataSource.class); this.jdbcTemplate2 = new JdbcTemplate(db2); ``` 以上xml配置或者代码塞进去都可以,idea中xml配置db1、db2会飘红,是不受影响的,idea编译的类型不对
d 接着正常测试就可以了 ``` String sql = "insert into test(id, name) values(6, '444')"; jdbcTemplate1.execute(sql); // 1库 jdbcTemplate2.execute(sql); // 2库 ``` d、其他的一些配置
百度上有的说在tomcat的server.xml中加入 ``` ``` 但是不加也能用,也没细究这个是干啥的
还有的说web.xml加 ``` PRTMAP DataSource jdbc_db1 javax.sql.DataSource Container ``` 但是不加也能用,也没细究这个是干啥的
2、集成全局事务框架,进行多数据源事务配置
jtom很久不更新了,而且资料比较旧不好搜,weblogic玩不明白,搞得atomikos
a pom文件 ``` com.atomikos transactions-jdbc 5.0.9 com.atomikos transactions-jdbc 5.0.9 ``` b spring中配置分布式事务 ``` ``` c 注解也加进去 ``` ``` d 无论@Transactional还是硬编码UserTransaction userTransaction = transactionManager.getUserTransaction();此处配置完测试是失败的,两个库直接数据报异常后并没有在一个事务管理器里
3、tomcat配置AXDataSource数据源,加入atomikosDataSourceBean
a atomikosDataSourceBean中设置的是XADatasource类型,所以tomcat之中要先把生成dataSource转为生成XADataSource类型
b 最终的配置 ``` ``` 注:
GenericNamingResourcesFactory是灵活依据类型生成的工厂,这个工厂可以生成DataSource、XADatasource或者其他;type中要配置com.mysql.cj.jdbc.MysqlXADataSource,配置javax.sql.XADataSource是不生效的;DataSource中配置的是username,而此处XADatasource配置的是user;链接字符串中要加上allowPublicKeyRetrieval,否则链接时候是报错的。
百度有些配置factory="com.atomikos.tomcat.EnhancedTomcatAtomikosBeanFactory"说是可以实现,但是没有找到这个jar是哪个。 c 测试XADatasource是否配置正确
需要先在mysql执行:`GRANT XA_RECOVER_ADMIN ON *.* TO root@'%' ;`(否则会报错的) ``` public void testJNDI() throws Exception{ Context ctx = new InitialContext(); XADataSource ds = (XADataSource) ctx.lookup("java:comp/env/jdbc_db1"); XAConnection conn = ds.getXAConnection(); System.out.println(conn.getConnection()); } ``` 运行完无报错,正常输入链接就ok了
d spring配置文件配置atomikosDataSourceBean ``` ``` e 测试全局事务 ``` public void test4() throws Exception{ // GRANT XA_RECOVER_ADMIN ON *.* TO root@'%' ; // Object db1 = applicationContextHelper.getApplicationContext().getBean("db1"); // XADataSource s= (XADataSource)db1; // XAConnection conn = s.getXAConnection(); // System.out.println(conn.getConnection()); UserTransaction userTransaction = transactionManager.getUserTransaction(); userTransaction.begin(); try { String sql = "insert into test(id, name) values(6, '444')"; jdbcTemplate1.execute(sql); jdbcTemplate2.execute(sql); userTransaction.commit(); } catch (Exception e) { userTransaction.rollback(); e.printStackTrace(); } } @Transactional public void test() throws Exception{ String sql = "insert into test(id, name) values(6, '444')"; jdbcTemplate1.execute(sql); // 1库 jdbcTemplate2.execute(sql); // 2库 } ``` 无论使用userTransaction还是@Transactional注解都是可以达到正常全局事务预期;第一次插入两个库均有数据,删除1库的id=6数据,再次执行,2库会有主键冲突,发现1库的数据也未插入。
### 三、分布式两阶段三阶段的弊端 1、两阶段:
a单点问题:协调者一旦宕机,所有参与者都会受到影响。如果协调者一直没 有恢复,没有正常发送 Commit 或者 Rollback 的指令,那所有参与者都必须一直等待。
b性能问题:两段提交过程中, 要经过两次远程服务调用,三次数据持久化(准备阶段写重做日志,协调者做状态持久 化,提交阶段在日志写入 Commit Record),整个过程将持续到参与者集群中最慢的那一个处理操作结束为止,这决定了两段式提交的性能通常都较差。
c 一致性风险:两段式提交的成立是有前提条件的,当网络稳定性和宕机 恢复能力的假设不成立时,仍可能出现一致性问题。如果协调者在发出准备指令后,根据 收到各个参与者发回的信息确定事务状态是可以提交的,协调者会先持久化事务状态,提交自己的事务,如果这时候网络忽然被断开,无法再通过网络向所有参与者发出 C ommit 指令的话,就会导致部分数据(协调者的)已提交,但部分数据(参与者的)既 未提交,也没有办法回滚,产生了数据不一致的问题。
2、三阶段:
a 三段式提交对单点问题和回滚时的性能问题有所改善,因为新增了 CanCommit, 是一个询问阶段
b在事务能够正常提交的场景中,三段式因为多了一次询问,还要比二段式稍微更差一些
c 一致性风险问题对比二段式并未有任何改进,在这方面它面临的风险甚至反而是略有增加了的。譬如, 进入 PreCommit 阶段之后,协调者发出的指令不是 Ack 而是 Abort,而此时因网络问题, 有部分参与者直至超时都未能收到协调者的 Abort 指令的话,这些参与者将会错误地提交 事务,这就产生了不同参与者之间数据不一致的问题
一些参考链接:
分布式事务两段提交原理: https://blog.csdn.net/weixin_42316952/article/details/112127814
分布式事务:https://www.kancloud.cn/luoyoub/microservice/2243036
两段和三段式事务:http://ddrv.cn/a/704480
### 四、Git也是一个多版本控制机制的实现,对比数据库多版本mvcc思考有哪些相同和不同之处,这些和数据库的隔离级别有什么关系?