# 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配置

spring配置atomikos的全局事务

jndi配置加载数据源


测试类


两个数据源在一个事务里,第一次插入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思考有哪些相同和不同之处,这些和数据库的隔离级别有什么关系?