JTA跨库分布式事务处理(二):分布式事务;借助JDBC处理大数据与事务关联(用若干对象模拟大数据)实例

分布式事务

由于整个系统涉及到很多服务 不同服务之间可能会对共享的数据并发的修改 导致数据的不一致性
分布式事务主要讨论的问题有:
	1.多进程并发修改共享数据如何保证数据一致性
	2.不同的请求之间数据如何进行隔离
	3.一个请求可能由多个服务共同完成,如何保证这些服务所有的操作要么同时成功要么同时失败?
	4.一个请求如果由三个服务共同完成,如果前两个服务成功了,最后一个服务失败了,如何保证数据的回滚?

在单服务的场景下,大多数场景下只需要增加@Transaction的注解
但是在分布式环境下,往往是多个进程对共享数据进行并发修改.

什么是事务

事务是一种可靠,一致的方式,是访问和操作数据库中的数据单元.
数据库中的事务:把多条SQL语句看成是一个整体的任务,这个整体的任务要么是语句全部执行成功,要么就是全部执行失败.
(ACID)特性

原子性(Atomicity):
事务就是一个不可以分割的工作单位,事务中的操作要么全部成功,要么全部失败.
比如:Batman转账给Superman的过程,一开始Batman有100元,Superman有100元,
Batman转账100元给Superman分为两个动作,分别是Batman扣除100元和Superman增加100元,
这两个动作要么共同发生,要么全部失败,体现的就是原子性.

一致性(Consistency):
事务必须使数据库从一个一致性状态变换为另外一个一致性状态.
比如:Batman和Superman各100元,转账之前加起来200元,转账之后两者账户加起来还是200元.

隔离性(Isolation):
事务的隔离性是指多个用户并发访问数据库的时候,数据库为每一个用户开启一个事务,不能被其他的事务干扰,多个并发事务之间要相互的隔离.
比如:Batman和Superman各100元,在Batman给Superman转账的过程中,Superman去查询自己的账户,此时产生两个事务,显示的金额体现了事务的隔离级别.

持久性(Dependence):
持久性就是指一旦一个事务被提交了之后,它对数据库的改变就是永久的,接下来即使是数据库发生了故障也不能够对这个事务有任何的影响.
比如:Batman转账100元给Superman,转账事务结束后,数据库即使发生了故障,也无法对该转账事务结果产生影响.

事务的隔离级别

名字 	隔离级别 	脏读 	不可重复读 	幻读 	数据库默认
可序列化 	Serializable 	否 	否 	否 				(等级最高 但占用系统资源更多)
可重复读 	Repeatable Read 	否 	否 	是 	MySQL			
读提交 	Read Committed 	否 	是 	是 	Oracle 和 SQL Server
读未提交 	Read Uncommited 	是 	是 	是 

脏读 : 就是一个事务读到了另外一个未提交的数据.
幻读 : 在你开启的事务中,读到了别的事务提交的新增插入的数据.
不可重复读:不可重复读是重复读取了另外一个事务已经提交了的数据,当你在一个事务中读两次,同时别的事务改变了数据并提交了事务,你两次读到的数据就不一致.
可重复读:在你的事务中,读到的数据以你第一次读到的为准,即使别的事务在你读到数据之后进行修改了并提交了,你也不会读到已经提交的数据.

之所以关注事务之间的隔离级别本质是因为在高并发情况下,多个线程或是进程会操作同一个数据库中的共享数据,此时有多个事务存在,此时数据库的隔离级别影响到了事务并发操作数据,
最安全的隔离级别是可序列化,在这个隔离级别下,所有的事务都是线性的,而不是并行的,就像是<使用Zookeeper实现分布式锁>中所介绍的悲观死锁一样.但是性能最差.在Mysql中我们可以使用for update为表或是表中的行加锁.

性能最好的事务隔离级别就是读未提交,但是这种事务隔离级别造成共享数据不安全性,也就是线程不安全的,在高并发下违背事务的一致性.

MySQL事务操作

MySql的事务隔离等级:可重复读

MySql中的锁机制

mysql中的锁根据级别划分为读锁和写锁

其中X锁也可以用于分布式锁的应用,但是高并发的X锁极大影响到了查询操作,非常影响性能和用户体验,所以不建议使用
1). 读锁(共享锁/S锁)
	当某个事务对这些数据加了读锁后,其他的事务只能对这些数据加读锁,也就是只能读取这些数据.
2). 写锁(排他锁/X锁)
	写锁的作用是某个事务对数据加了写锁之后,其他事务不能对这些数据加任何锁。
	借助JDBC处理大数据与事务关联(用若干对象模拟大数据)

借助JDBC处理大数据与事务关联(用若干对象模拟大数据)
1.准备Dept类

public class Dept {
	
	private int id;
	private String uname;
	private String upwd;
	
	public Dept(int id, String uname, String upwd) {
		super();
		this.id = id;
		this.uname = uname;
		this.upwd = upwd;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getUname() {
		return uname;
	}

	public void setUname(String uname) {
		this.uname = uname;
	}

	public String getUpwd() {
		return upwd;
	}

	public void setUpwd(String upwd) {
		this.upwd = upwd;
	}
}

2.测试类

public class BigDataTest {

	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		 String constr = "jdbc:mysql://localhost:3306/mybatis0202";
		 String uname = "root";
		 String upwd = "zzj6660534";
		 
		 Connection conn = null;
		 Statement stmt = null;
		 
		 Dept d1 = new Dept(1, "lisi", "123");
		 Dept d2 = new Dept(2, "lisi", "123");
		 Dept d3 = new Dept(3, "lisi", "123");
		 Dept d4 = new Dept(4, "lisi", "123");
		 Dept d5 = new Dept(5, "lisi", "123");
		 Dept d6 = new Dept(6, "lisi", "123");
		 Dept d7 = new Dept(7, "lisi", "123");
		 Dept d8 = new Dept(8, "lisi", "123");
		 Dept d9 = new Dept(9, "lisi", "123");
		 Dept d10 = new Dept(10, "lisi", "123");
		 Dept d11 = new Dept(11, "lisi", "123");
		 
		 List<Dept> depts = new ArrayList<Dept>();
		 depts.add(d1);
		 depts.add(d2);
		 depts.add(d3);
		 depts.add(d4);
		 depts.add(d5);
		 depts.add(d6);
		 depts.add(d7);
		 depts.add(d8);
		 depts.add(d9);
		 depts.add(d10);
		 depts.add(d11);
		 
		 Class.forName("com.mysql.jdbc.Driver");
		 conn = DriverManager.getConnection(constr, uname, upwd);
		 stmt = conn.createStatement();
		 conn.setAutoCommit(false);
		 int beatchNum = 0;//计数器
		 for(int i = 0; i<depts.size(); i++) {
			 //缓存不提交
			 stmt.addBatch("insert into dept(id,uname,upwd) values("+depts.get(i).getId()+",'"+depts.get(i).getUname()+"','"+depts.get(i).getUpwd()+"')");
			 
			 beatchNum += 1;
			 
			//如果被5整除进行提交缓存(每五条进行提交缓存)
			 if(beatchNum % 5 == 0) {
				 //执行缓存区所有语句
				 stmt.executeBatch();
				 conn.commit();
				 System.out.println("提交");
			 }
		 }
		 stmt.executeBatch();
		 conn.commit();
		 System.out.println("全部提交");
		 
		 stmt.close();
		 conn.close();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值