自动分表
2015-09-16 00:19
246 查看
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.Date; public abstract class AIPkCountSplitTable<T> { public abstract T mapRsRow(ResultSet rs) throws SQLException; public abstract boolean createTable(Connection con, int autokeyStart) throws SQLException; private String tableName; private String pkColName; private int splitCount; public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getPkColName() { return pkColName; } public void setPkColName(String pkColName) { this.pkColName = pkColName; } public int getSplitCount() { return splitCount; } public void setSplitCount(int splitCount) { this.splitCount = splitCount; } private void setStmtArg(PreparedStatement prepStatement, Object[] params) throws SQLException { if(null == params) return; for(int i = 0; i < params.length; ++i) { Object param = params[i]; if (param instanceof Integer) { int value = ((Integer) param).intValue(); prepStatement.setInt(i + 1, value); } else if (param instanceof String) { String s = (String) param; prepStatement.setString(i + 1, s); } else if (param instanceof Double) { double d = ((Double) param).doubleValue(); prepStatement.setDouble(i + 1, d); } else if (param instanceof Float) { float f = ((Float) param).floatValue(); prepStatement.setFloat(i + 1, f); } else if (param instanceof Long) { long l = ((Long) param).longValue(); prepStatement.setLong(i + 1, l); } else if (param instanceof Boolean) { boolean b = ((Boolean) param).booleanValue(); prepStatement.setBoolean(i + 1, b); } else if (param instanceof Date) { Date d = (Date) param; prepStatement.setDate(i+1, new java.sql.Date(d.getTime())); } } } private boolean renameTable(Connection con, int tbIdx) throws SQLException{ String newTableName = tableName + tbIdx; String sql = "RENAME TABLE " + tableName + " TO " + newTableName; Statement st = con.createStatement(); st.executeUpdate(sql); return true; } private int selectMaxId(Connection con) throws SQLException{ int maxId = -1; String sql = "SELECT MAX("+ pkColName +") FROM " + tableName; PreparedStatement st = con.prepareStatement(sql); ResultSet rs = st.executeQuery(sql); if(rs.next()) maxId = rs.getInt(1); rs.close(); return maxId; } private int selectCount(Connection con, String tbname, String sqlWhere, Object[] args) throws SQLException { int cnt = 0; String sql = "SELECT COUNT(*) FROM " + tbname + " " + sqlWhere; PreparedStatement st = con.prepareStatement(sql); this.setStmtArg(st, args); ResultSet rs = st.executeQuery(sql); if(rs.next()) cnt = rs.getInt(1); rs.close(); return cnt; } public boolean deleteById(Connection con, int id) throws SQLException { try{ String sql = "DELETE FROM " + tableName + " WHERE " + pkColName + "=?"; PreparedStatement st = con.prepareStatement(sql); st.setInt(1, id); if(1 == st.executeUpdate()) return true; }catch(SQLException ex){} int idx = id / splitCount; String acTableName = this.tableName + idx; String sql2 = "DELETE FROM " + acTableName + " WHERE " + pkColName + "=?"; PreparedStatement st2 = con.prepareStatement(sql2); st2.setInt(1, id); if(1 == st2.executeUpdate()) return true; return false; } // where xxx=? and yyy=? public int delete(Connection con, String sqlWhere, Object[] args) throws SQLException { int nupdate = 0; int maxId = selectMaxId(con); int tableIdx = maxId / splitCount; ++tableIdx; for(int i = 0 ; i < tableIdx; ++i){ String subTableName = ""; if(i == tableIdx-1) subTableName = this.tableName; else subTableName = this.tableName + i; String sql = "DELETE FROM " + subTableName + " " + sqlWhere; PreparedStatement st = con.prepareStatement(sql); this.setStmtArg(st, args); nupdate += st.executeUpdate(); } return nupdate; } private boolean innerInsert(Connection con, PreparedStatement insStmt, T value, PreparedStmtParamSetter<T> paramSetter) throws SQLException { int id = -1; paramSetter.setParams(insStmt, value); if(1 == insStmt.executeUpdate()){ ResultSet keys = insStmt.getGeneratedKeys(); if(keys.next()){ Integer generatedId = keys.getInt(1); id = generatedId.intValue(); }else{ return false;} }else{ return false;} // 达到分表灵界先删除插入成功的,从旧表中删除,生成新表在插入 // 保证新建的表中有一条数据,select Max(pk) 才管用 if(0 == id % this.splitCount){ String delSql = "DELETE FROM " + this.tableName + " WHERE " + this.pkColName + "=" + id; Statement delStmt = con.createStatement(); if(1 != delStmt.executeUpdate(delSql)) return false; // 从0开始命名表,才能用 id/splitCount直接做表名索引 1999/2000 = 0, 2000/2000=1,2000在表1中 int tbIdx = id / splitCount - 1 ; renameTable(con, tbIdx); createTable(con, id); paramSetter.setParams(insStmt, value); if(1 == insStmt.executeUpdate()){ ResultSet keys = insStmt.getGeneratedKeys(); if(keys.next()){ Integer generatedId = keys.getInt(1); id = generatedId.intValue(); }else{ return false;} }else{ return false;} } paramSetter.setId(value, id); return true; } //" (col1, col2) values(?, 1,?)" public boolean insert(Connection con, String sql, T value, PreparedStmtParamSetter<T> paramSetter) throws SQLException{ String insSql = "INSERT INTO " + this.tableName + sql; PreparedStatement insStmt = con.prepareStatement(insSql,Statement.RETURN_GENERATED_KEYS); return innerInsert(con, insStmt, value, paramSetter); } public boolean insertBatch(Connection con, String sql, List<T> values, PreparedStmtParamSetter<T> paramSetter) throws SQLException { if(null == values || values.size() == 0) return true; String insSql = "INSERT INTO " + this.tableName + sql; PreparedStatement insStmt = con.prepareStatement(insSql,Statement.RETURN_GENERATED_KEYS); for(int i = 0; i < values.size(); ++i) { T value = values.get(i); if(!innerInsert(con, insStmt, value, paramSetter)) return false; } return true; } private List<T> innerSelectAll(Connection con, String sqlWhere, Object[] args, int startTbIdx) throws SQLException { // 5999/2000 = 2,以前有0,1两张表 int maxId = selectMaxId(con); int tableIdx = maxId / splitCount; ++tableIdx; // 加成3,表名索引为2,就是当前表了,便于在一个循环中处理完 List<T> elems = new ArrayList<T>(); for(int i = startTbIdx ; i < tableIdx; ++i){ String subTableName = ""; if(i == tableIdx-1) subTableName = this.tableName; else subTableName = this.tableName + i; String sql = "SELECT * FROM " + subTableName + " " + sqlWhere; PreparedStatement st = con.prepareStatement(sql); this.setStmtArg(st, args); ResultSet rs = st.executeQuery(); while(rs.next()){ elems.add(mapRsRow(rs)); } rs.close(); } return elems; } // where xx=? public List<T> select(Connection con, String sqlWhere, Object[] args) throws SQLException { return innerSelectAll(con, sqlWhere, args, 0); } // 15 30 20 45 public List<T> selectPage(Connection con, String sqlWhere, Object[] args, int offset, int limit) throws SQLException { int maxId = selectMaxId(con); int tableIdx = maxId / splitCount; ++tableIdx; List<T> elems = new ArrayList<T>(); int startTbIdx = tableIdx; int offsetCnt = 0; // 找到偏移起始表索引 if(0 != offset){ for(int i = 0 ; i < tableIdx; ++i){ String subTableName = ""; if(i == tableIdx-1) subTableName = this.tableName; else subTableName = this.tableName + i; int cnt = this.selectCount(con, subTableName, sqlWhere, args); offsetCnt += cnt; // 累计条数,0-i个表中的条数超过offset,说明要从第i个表开始偏移 if(offsetCnt > offset){ // offset 减去 0到i-1的总条数,就是在当前表中的偏移 offset = offset - (offsetCnt-cnt); startTbIdx = i; break; } } } if(startTbIdx >= tableIdx) return elems; if(-1 == limit) return innerSelectAll(con, sqlWhere, args, startTbIdx); int newLimit = limit; for(int i = startTbIdx ; i < tableIdx; ++i){ String subTableName = ""; if(i == tableIdx-1) subTableName = this.tableName; else subTableName = this.tableName + i; String sql = "SELECT * FROM " + subTableName + " " + sqlWhere + "LIMIT " + offset + "," + newLimit; PreparedStatement st = con.prepareStatement(sql); this.setStmtArg(st, args); ResultSet rs = st.executeQuery(); while(rs.next()){ elems.add(mapRsRow(rs)); --newLimit; } rs.close(); offset = 0; // 只是第一张需要偏移 if(newLimit <= 0) // never less than break; } return elems; } public T selectById(Connection con, int id) throws SQLException{ T elem = null; String sql = "SELECT * FROM " + this.tableName + " WHERE " + this.pkColName + "=?"; PreparedStatement st = con.prepareStatement(sql); st.setInt(1, id); ResultSet rs = st.executeQuery(); if(rs.next()) elem = mapRsRow(rs); rs.close(); if(null != elem) return elem; int idx = id / splitCount; String acTableName = this.tableName + idx; String sql2 = "SELECT * FROM " + acTableName + " WHERE " + this.pkColName + "=?"; PreparedStatement st2 = con.prepareStatement(sql2); st2.setInt(1, id); ResultSet rs2 = st2.executeQuery(); if(rs2.next()) elem = mapRsRow(rs2); rs2.close(); return elem; } // set xx=?, yy=? public boolean updateById(Connection con, String setSql, Object[] args, int id) throws SQLException { try{ String sql1 = "UPDATE " + this.tableName + " " + setSql + " WHERE " + this.pkColName + "=?"; PreparedStatement st1 = con.prepareStatement(sql1); this.setStmtArg(st1, args); st1.setInt(args.length+1, id); if(1 == st1.executeUpdate()) return true; }catch(SQLException e){} int idx = id / splitCount; String acTableName = this.tableName + idx; String sql2 = "UPDATE " + acTableName + " "+ setSql + " WHERE " + this.pkColName + "=?"; PreparedStatement st2 = con.prepareStatement(sql2); this.setStmtArg(st2, args); st2.setInt(args.length+1, id); if(1 == st2.executeUpdate()) return true; return false; } // set xx=?, yy =? where cc=? and zz=2 public int update(Connection con, String setSql, Object[] args) throws SQLException { int nupdate = 0; int maxId = selectMaxId(con); int tableIdx = maxId / splitCount; ++tableIdx; for(int i = 0 ; i < tableIdx; ++i){ String subTableName = ""; if(i == tableIdx-1) subTableName = this.tableName; else subTableName = this.tableName + i; String sql = "UPDATE " + subTableName + " " + setSql; PreparedStatement st = con.prepareStatement(sql); this.setStmtArg(st, args); nupdate += st.executeUpdate(); } return nupdate; } }
相关文章推荐
- 【LeetCode】Integer to English Words 解题报告
- dojo/dom源码学习
- POJ 1753 Flip Game
- sparksql性能调优
- POJ - 1703 Find them, Catch them(带权并查集)
- Python中的Berkeley DB(1):Hello Berkeley DB
- C语言之位操作符
- hdoj 2842 Chinese Rings 【递推 + 矩阵快速幂】
- Hadoop(六)——子项目Pig
- 关于win7系统的Oracle安装时的[INS-30131]问题的解决方案
- 初识OS
- TestNG 入门教程
- Servlet获取请求参数、表单验证(2015.9.15)
- 求解最大子数组问题
- 面试中的Singleton【转】
- java中的多继承
- Understanding hibernate first level cache with example
- 9月10日课程作业(练习)
- 省市县三级联动
- [LeetCode] Single Number III