数据库的分库 分表 分中心 实现简记

1.分库:

是将在一个用户下的表分到多个用户下(物理上可能是同一个库,也可以是不同的库,用户下的表不重复)。例如:把库分为配置库和实例库。或者把库拆为:产品库 订单库等。

2.分表:

在表的后面添加分表标志。例如A_110 , A_111 ,A_112等

3.分中心:

将一套表部署到多个库中。(物理上可能是同一个库,也可以是不同的库,用户下的表重复

1.在分库的条件下,要保持事务一致性。要么所有用户全部提交,要么所有用户全部回滚。

2.在保存数据时,要确定插入的数据要在哪个分表,哪个中心。

(1)分库事务一致性的解决:

正常情况下,事务的封装,都是定义一个事务对象,事务对象中有一个数据库连接。

分库的条件下,可以在事务对象中维护一个容器,存放多个数据库连接。要么一起提交,要么一起回滚。保证事务的一致性。

事物封装的简单实现,在分库的情况下,保证事物的一致性。

1.事物对象的封装

public class BasicTransAction extends AbstractTransaction {
   private Log log = LogFactory.getLog(BasicTransAction.class);
   private static ThreadLocal<Stack<ThreadInfo>> suspend = new ThreadLocal<Stack<ThreadInfo>>();
   private static ThreadLocal<ThreadInfo> curThread = new ThreadLocal<ThreadInfo>();
   private class ThreadInfo{
         public DataSource curDs;
      public Map<String,Connection> connection = new HashMap<String,Connection>();
      public String threadName;
      public String txid;
      public ThreadInfo(){
         this.txid=Thread.currentThread().getId()+"";
         this.threadName=Thread.currentThread().getName()+System.currentTimeMillis();
      }
   }

封装一个内部的事物对象,注意事务对象内部 连接是通过 HashMap存储,这样事务对象可以保存多个数据源的连接Connection。

事物对象信息可以根据自己的需要进行封装。例如:可以增加事物的开始时间,事物的超时时间。这样可以控制事物超时的时候,直接抛出异常。

2.启动事物

private static ThreadLocal<Stack<ThreadInfo>> suspend = new ThreadLocal<Stack<ThreadInfo>>();
private static ThreadLocal<ThreadInfo> curThread = new ThreadLocal<ThreadInfo>();
public void startTransaction()throws Exception{
   if(isStartTransaction()){
      throw new Exception("已经启动事务,若想再启事务,请先挂起当前事务");
   }
   ThreadInfo thread =new ThreadInfo();
   System.out.println("开启事务"+thread.threadName);
   curThread.set(thread);
}

创建事物对象,将其放入到threadlocal中。

3.获取数据库连接

public Connection _getConnection(String ds)throws Exception{
   if(isStartTransaction()){//如果启动了事物
      ThreadInfo thread = curThread.get();
      if(thread.connection.containsKey(ds)){//校验事物对象中是否已经有该数据源的连接,有连接直接返回,没有连接从数据源中获取连接
         thread.curDs=DataSourceManagerFactory.getDatasourceManager().getDataSource(ds);
         return thread.connection.get(ds);//将连接放入当前事务
      }
      Connection conn = DataSourceManagerFactory.getDatasourceManager().getConnection(ds);
      thread.connection.put(ds, conn);
      thread.curDs=DataSourceManagerFactory.getDatasourceManager().getDataSource(ds);
      conn.setAutoCommit(false);
      return conn;
   }else{
      return DataSourceManagerFactory.getDatasourceManager().getConnection(ds);
   }
}

4.校验是否开启事物

public boolean isStartTransaction()throws Exception{
   return curThread.get()!=null;
}

5.挂起事物

private static ThreadLocal<Stack<ThreadInfo>> suspend = new ThreadLocal<Stack<ThreadInfo>>();
private void addSuspend(ThreadInfo thread)throws Exception{
   if(suspend.get()==null){
      suspend.set(new Stack<ThreadInfo>());
   }
   suspend.get().add(thread);
}
public void suspendTransaction()throws Exception{
   if(!isStartTransaction()){
      throw new Exception("没有当前事务,无法挂起");
   }
   addSuspend(curThread.get());//将当前事务放到suspend 
   curThread.remove();//清空当前事务对象
   curThread.set(null);
}

将当前的事物对象从curThread中移除放到suspend(ThreadLocal)中,suspend中存放的是栈:后进先出。

6.事物恢复

public void resume()throws Exception{
   if(isStartTransaction()){
      log.error("当前事务未作处理,事物信息会丢失,且连接泄漏");   
   }
   Stack<ThreadInfo> stack= suspend.get();
   if(stack == null || stack.size() <=0){
      log.error("无挂起事物,无法恢复");
   }
   curThread.set(null);
   curThread.set(stack.pop());
}

将suspend中最后进入的事物取出,放到当前事务中。

7.事物提交

public void commitTransAction()throws Exception{
   if(!isStartTransaction()){
      throw new Exception("没有当前事务,无法提交");
   }
   ThreadInfo thread = curThread.get();
   System.out.println("提交事务"+thread.threadName);
   try {
      Connection conn=null;
      boolean isCommit=true;
      for(Iterator it = thread.connection.keySet().iterator();it.hasNext();){
         try {
            conn=thread.connection.get(it.next());
            commit(conn, isCommit);
         } catch (Exception e) {
            if(log.isErrorEnabled())
               log.error(e.getMessage(), e);
            isCommit=false;
            commit(conn, isCommit);
         }finally{
            if(!conn.isClosed())
               conn.close();
         }
      }
   } catch (Exception e) {
      if(log.isErrorEnabled())
         log.error(e.getMessage(), e);
   }finally{
      clearThreadInfo();//清楚当前的事物信息
   }
}
private void commit(Connection conn,boolean isCommit)throws Exception{
   if(isCommit){
      conn.commit();
   }else{
      conn.rollback();
   }
}

获取当前事务的所有连接,循环提交事务。这样多个数据源的连接就同时提交了。这里有一个问题:就是如果一个连接提交成功,然后后面的连接提交失败,未提交的连接会回滚,已提交的连接无法回滚,但是,如果sql有问题,一般都是在执行的时候报出错误信息,连接提交的时候很少会出错。

8.事物回滚

public void rollBackTransaction(){


   try {
      if(!isStartTransaction()){
         throw new Exception("没有当前事务,无法回滚");
      }
      ThreadInfo thread = curThread.get();
      Connection conn=null;
      boolean isCommit=false;
      for(Iterator it = thread.connection.keySet().iterator();it.hasNext();){
         try {
            conn=thread.connection.get(it.next());
            commit(conn, isCommit);
         } catch (Exception e) {
            if(log.isErrorEnabled())
               log.error(e.getMessage(), e);
         }finally{
            if(!conn.isClosed())
               conn.close();
         }
      }
   } catch (Exception e) {
      if(log.isErrorEnabled())
         log.error(e.getMessage(), e);
   }finally{
      clearThreadInfo();
   }

}

获取当前事务的所有连接,循环回滚事务

9.使用方式

boolean isStartTransaction=false;
try {
    isStartTransaction = SessionFactory.getSession().isStartTransaction();//判断当前是否已经启用事物
   if(isStartTransaction){
      SessionFactory.getSession().suspendTransaction();//如果启动,挂起当前事务
   }
   SessionFactory.getSession().startTransaction();//开启新事物
  
   SessionFactory.getSession().commitTransAction();//事物提交
} catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   SessionFactory.getSession().rollBackTransaction();//事物回滚
   
}finally{
   if(isStartTransaction)
      SessionFactory.getSession().resume();//如果前面挂起事物,进行实物恢复
}

以上是一个在一个线程中多数据源的事物封装的简单实现,基本上能够保证多数据源的书屋一致性。由于时间比较紧,没有做过多的优化,主要是事物封装思想。若要使用,还需要添加以下内容。

1.方法和数据源的映射关系。在多数据源的情况下,该方法应该使用哪个数据源。这里可以采用注解配置,或者在分包明确的情况下,直接采用 类路径和数据源的映射。

(2)分表 分中心的确认

根据某一个特性,采用适合的映射算法,映射到不同的分表, 例如取余等。然后维护一个分表和分中心的关系。

 

整合spring的思想。

1.重写spring的事务对象。

2.重写事务管理器。

3.修改mybatis的sql执行类。在执行sql前,把sql语句的需要分表的表计算出对应的分表。

4.标志当前表在哪个用户下。可以给mapper文件添加标签,或者通过路径进行匹配对应的用户(数据源)

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值