并发环境下mysql插入检查方案
业务背景: 解决方案一: ALTER tableName ADD UNIQUE [indexName] ON (tableColumns(length)) 但是由于业务限制,vin在库中是可以重复的,多条重复数据查询最新,所以不能再vin上添加唯一索引。 解决方案二: public static void StartTransaction(Connection con,String[] sqls) throws Exception { try { // 事务开始 con.setAutoCommit(false); // 设置连接不自动提交,即用该连接进行的操作都不更新到数据库 sm = con.createStatement(); // 创建Statement对象 //依次执行传入的SQL语句 for (int i = 0; i < sqls.length; i++) { sm.execute(sqls[i]);// 执行添加事物的语句 } con.commit(); // 提交给数据库处理 // 事务结束 //捕获执行SQL语句组中的异常 } catch (SQLException e) { try { System.out.println("事务执行失败,进行回滚!n"); con.rollback(); // 若前面某条语句出现异常时,进行回滚,取消前面执行的所有操作 } catch (SQLException e1) { e1.printStackTrace(); } } finally { sm.close(); } } 但是这样实际上还是没有解决并发的问题,这样只是把两个操作变成了一个原子的sql操作,可以用于同时插入两条数据一致性的情况,但并不适合需求。 既然sql层面没有解决问题,就考虑从java的并发编程方向解决。 synchronized(this){ //todo1:检查vin是否存在 //todo2:如果不存在插入vin } ?可重入锁: public class DashengCallBack extends HttpServlet { private static ReentrantLock lock= new ReentrantLock(); protected void doGet(HttpServletRequest request,HttpServletResponse response){ lock.lock(); try{ //todo1:检查vin是否存在 //todo2:如果不存在插入vin }finally{ lock.unlock(); } } } 经过测试,这个方案是可行的,最终没有采用的原因是因为直接使用这种方式加锁,加锁的代码太多,影响效率。 解决方案四: ConcurrentHashMap<String,String> vinMap=new ConcurrentHashMap<String,String>(); if(vinMap.containsKey(vin)){ // todo1: vin 请求完毕后,从vinInRequestMap里删掉这个vinNo // todo2: 返回正在查询 } vinMap.put(vin,""); //todo3:插入vin到数据库 vinMap.remove(vin); } 这个方案基本满足了业务需求,唯一的问题是要求接口的更新时间要与业务时间错开,否则更新接口会清空vinMap,导致库中数据混乱,出现错误。 以上就是本文的全部内容,希望对大家的学习有所帮助。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |