-------前篇:手写DAO框架(三)-数据库链接---------html
经过上一篇写的方法,能够灵活的获取、释放数据库链接,拿到链接以后,咱们就能够执行sql了!因此,本篇介绍的就是SQL执行器。java
SQL执行器主要功能就是执行sql,返回结果。如新增、更新、删除、查询,其中也涉及到了事务的开启、关闭、回滚。python
这一层的定位是为接下来的DAO层提供底层支持,同时也支持自行编写SQL进行直接调用。sql
本篇主要涉及技术有:泛型、匿名内部类。数据库
说到泛型,先简单的对比一下python和java,在python中,一个方法能够有多个同类型或者不一样类型的返回值;而在java里面,方法的返回值类型必须是肯定。编程
在java里面,若是返回多个同类型的,能够直接经过一个数组或者集合来作。若是要返回多个不一样类型的,就只能定义一个包装类了。若是不用泛型,定义的这些包装类就只能适用于不多部分方法。可是若是用了泛型(其实也包装了继承和类的初始化),这个包装类就厉害,能够只关注数量,不关注具体类型。我以前没有想到这么用,是后来看《Java编程思想》的时候才发现的。数组
举个🌰:框架
包含两个类的TwoTuple:ide
1 package me.lovegao.gdao.bean; 2 3 public class TwoTuple<A, B> { 4 public final A a; 5 public final B b; 6 7 public TwoTuple(A a, B b) { 8 this.a = a; 9 this.b = b; 10 } 11 }
包含三个类的ThreeTuple:post
1 package me.lovegao.gdao.bean; 2 3 public class ThreeTuple<A, B, C> extends TwoTuple<A, B> { 4 public final C c; 5 6 public ThreeTuple(A a, B b, C c) { 7 super(a, b); 8 this.c = c; 9 } 10 }
若是有4个、5个的需求,能够继续写下来。
接下来就进入正式的代码环节。
同样是面向接口编程,先定义接口
1 package me.lovegao.gdao.sqlexecute; 2 3 import java.util.List; 4 5 import me.lovegao.gdao.bean.TwoTuple; 6 7 /** 8 * sql执行接口 9 * @author simple 10 * 11 */ 12 public interface ISqlExecutor { 13 /** 14 * 查询 15 * @param sql sql语句 16 * @param params 参数值 17 * @return 值列表 18 */ 19 List<Object[]> query(String sql, Object[] params) throws Exception; 20 21 /** 22 * 查询值,和对应的数据库列名 23 * @param sql 24 * @param params 25 * @return 26 * @throws Exception 27 */ 28 TwoTuple<List<Object[]>, String[]> queryValueAndColumn(String sql, Object[] params) throws Exception; 29 30 /** 31 * 插入数据 32 * @param sql 插入sql 33 * @param params 参数值 34 * @return 插入数据的id 35 */ 36 <T> T insert(String sql, Object[] params) throws Exception; 37 38 /** 39 * 批量插入 40 * @param sql 41 * @param paramsList 42 * @return 43 */ 44 int[] insertOrUpdateBatch(String sql, List<Object[]> paramsList) throws Exception; 45 46 /** 47 * 更新数据 48 * @param sql 49 * @param params 50 * @return 51 */ 52 int update(String sql, Object[] params) throws Exception; 53 54 }
sql执行接口定义以后,还须要定义一个包含事务功能的接口,以便使用事务的功能。
1 package me.lovegao.gdao.sqlexecute; 2 3 /** 4 * 包含主动进行事务控制的sql执行器 5 * @author simple 6 * 7 */ 8 public interface IManulTransactionSqlExecutor extends ISqlExecutor { 9 /** 10 * 开启事务 11 * @throws Exception 12 */ 13 public void beginTransaction() throws Exception; 14 15 /** 16 * 开启事务 17 * @param transactionIsolationLevel 事务传播级别 one of the following <code>Connection</code> constants: 18 * <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>, 19 * <code>Connection.TRANSACTION_READ_COMMITTED</code>, 20 * <code>Connection.TRANSACTION_REPEATABLE_READ</code>, or 21 * <code>Connection.TRANSACTION_SERIALIZABLE</code>. 22 * (Note that <code>Connection.TRANSACTION_NONE</code> cannot be used 23 * because it specifies that transactions are not supported.) 24 * @throws Exception 25 */ 26 public void beginTransaction(int transactionIsolationLevel) throws Exception; 27 28 /** 29 * 提交事务 30 * @throws Exception 31 */ 32 public void commitTransaction() throws Exception; 33 34 /** 35 * 回滚事务 36 * @throws Exception 37 */ 38 public void rollbackTransaction() throws Exception; 39 }
由于进行事务控制的同时,还得须要sql执行,因此就采起了接口继承(其实Java里面有多继承,只不过是接口之间)。
接口定义完成以后,就是具体实现了。
1 package me.lovegao.gdao.sqlexecute; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.ResultSetMetaData; 7 import java.sql.Statement; 8 import java.util.ArrayList; 9 import java.util.List; 10 11 import me.lovegao.gdao.bean.TwoTuple; 12 import me.lovegao.gdao.connection.IConnectionPool; 13 import me.lovegao.gdao.util.GDaoCommonUtil; 14 import me.lovegao.gdao.util.JDBCUtil; 15 16 /** 17 * sql执行类 18 * @author simple 19 * 20 */ 21 public class SimpleSqlExecutor implements ISqlExecutor, IManulTransactionSqlExecutor { 22 private ThreadLocal<Connection> CONNECTION_THREAD_LOCAL = new ThreadLocal(); 23 private IConnectionPool connectionPool; 24 /**默认事务隔离级别**/ 25 private static int DEFAULT_TRANSACTION_ISOLATION_LEVEL = Connection.TRANSACTION_READ_COMMITTED; 26 /**查询超时时间-秒**/ 27 private int queryTimeoutSeconds; 28 29 public SimpleSqlExecutor(IConnectionPool connectionPool) { 30 this.connectionPool = connectionPool; 31 this.queryTimeoutSeconds = connectionPool.getQueryTimeoutSecond(); 32 } 33 34 //获取链接 35 private Connection getConnection() throws Exception { 36 Connection conn = CONNECTION_THREAD_LOCAL.get(); 37 if(conn == null) { 38 conn = connectionPool.getConnection(); 39 conn.setTransactionIsolation(DEFAULT_TRANSACTION_ISOLATION_LEVEL); 40 conn.setAutoCommit(true); 41 CONNECTION_THREAD_LOCAL.set(conn); 42 } 43 return conn; 44 } 45 46 //释放链接 47 private void releaseConnection() { 48 Connection conn = CONNECTION_THREAD_LOCAL.get(); 49 if(conn != null) { 50 CONNECTION_THREAD_LOCAL.remove(); 51 connectionPool.returnConnection(conn); 52 } 53 } 54 55 /** 56 * 通用sql执行 57 * @param sql 58 * @param params 59 * @param preparedStatementResolve 60 * @return 61 * @throws Exception 62 */ 63 private <T> T generalSqlExecute(String sql, Object[] params, boolean returnKeys, 64 IPreparedStatementResolve<T> preparedStatementResolve) throws Exception { 65 T t = null; 66 Connection conn = null; 67 PreparedStatement ps = null; 68 try { 69 conn = getConnection(); 70 if(returnKeys) { 71 ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); 72 } else { 73 ps = conn.prepareStatement(sql); 74 } 75 ps.setQueryTimeout(queryTimeoutSeconds); 76 if(!GDaoCommonUtil.checkCollectionEmpty(params)) { 77 for(int i=0; i<params.length; i++) { 78 ps.setObject(i+1, params[i]); 79 } 80 } 81 t = preparedStatementResolve.solvePreparedStatement(ps); 82 } catch (Exception e) { 83 throw e; 84 } finally { 85 JDBCUtil.closePreparedStatement(ps); 86 releaseConnection(); 87 } 88 return t; 89 } 90 91 /** 92 * 查询 93 * @param sql 查询sql 94 * @param params sql中?对应的值 95 * @param needColumn 是否须要列名 96 * @return 97 * @throws Exception 98 */ 99 private TwoTuple<List<Object[]>, String[]> query(String sql, Object[] params, boolean needColumnName) throws Exception { 100 TwoTuple<List<Object[]>, String[]> tuple = generalSqlExecute(sql, params, false, new IPreparedStatementResolve<TwoTuple<List<Object[]>, String[]>>() { 101 @Override 102 public TwoTuple<List<Object[]>, String[]> solvePreparedStatement(PreparedStatement ps) throws Exception { 103 List<Object[]> localList = new ArrayList(); 104 String[] columns = null; 105 ResultSet rs = ps.executeQuery(); 106 ResultSetMetaData metaData = rs.getMetaData(); 107 int columnCount = metaData.getColumnCount(); 108 if(needColumnName) { 109 columns = new String[columnCount]; 110 for(int i=1; i<=columnCount; i++) { 111 columns[i-1] = metaData.getColumnName(i); 112 } 113 } 114 while(rs.next()) { 115 Object[] rowData = new Object[columnCount]; 116 for(int i=1; i<=columnCount; i++) { 117 rowData[i-1] = rs.getObject(i); 118 } 119 localList.add(rowData); 120 } 121 JDBCUtil.closeResultSet(rs); 122 return new TwoTuple<List<Object[]>, String[]>(localList, columns); 123 } 124 }); 125 return tuple; 126 } 127 128 @Override 129 public List<Object[]> query(String sql, Object[] params) throws Exception { 130 List<Object[]> list = new ArrayList(); 131 TwoTuple<List<Object[]>, String[]> tuple = query(sql, params, false); 132 if(tuple != null) { 133 list = tuple.a; 134 } 135 return list; 136 } 137 138 @Override 139 public TwoTuple<List<Object[]>, String[]> queryValueAndColumn(String sql, Object[] params) throws Exception { 140 TwoTuple<List<Object[]>, String[]> tuple = query(sql, params, true); 141 return tuple; 142 } 143 144 145 @Override 146 public <T> T insert(String sql, Object[] params) throws Exception { 147 T pk = null; 148 pk = generalSqlExecute(sql, params, true, new IPreparedStatementResolve<T>() { 149 @Override 150 public T solvePreparedStatement(PreparedStatement ps) throws Exception { 151 T id = null; 152 ps.executeUpdate(); 153 ResultSet rs = ps.getGeneratedKeys(); 154 if(rs.next()) { 155 id = (T) rs.getObject(1); 156 } 157 JDBCUtil.closeResultSet(rs); 158 return id; 159 } 160 }); 161 return pk; 162 } 163 164 @Override 165 public int[] insertOrUpdateBatch(String sql, List<Object[]> paramsList) throws Exception { 166 int[] res = null; 167 Connection conn = null; 168 PreparedStatement ps = null; 169 //是否改变了自动提交,防止此事务外还有其余事务 170 //一、若是默认是手动提交,说明外界修改了自动提交,即外界要本身控制提交、回滚操做,则后续的提交、回滚操做不主动触发。 171 //二、若是默认是自动提交,后续则触发提交、回滚操做 172 boolean changeAutoCommit = false; 173 try { 174 conn = getConnection(); 175 //默认是主动提交 176 if(changeAutoCommit = conn.getAutoCommit()) { 177 //改成非自动提交 178 conn.setAutoCommit(false); 179 } 180 ps = conn.prepareStatement(sql); 181 ps.setQueryTimeout(queryTimeoutSeconds); 182 if(!GDaoCommonUtil.checkCollectionEmpty(paramsList)) { 183 for(Object[] params : paramsList) { 184 for(int i=0; i<params.length; i++) { 185 ps.setObject(i+1, params[i]); 186 } 187 ps.addBatch(); 188 } 189 } 190 res = ps.executeBatch(); 191 if(changeAutoCommit) { 192 conn.commit(); 193 } 194 } catch (Exception e) { 195 if(changeAutoCommit) { 196 conn.rollback(); 197 } 198 throw e; 199 } finally { 200 if(ps != null) { 201 ps.close(); 202 } 203 if(conn != null && changeAutoCommit) { 204 conn.setAutoCommit(true); 205 releaseConnection(); 206 } 207 } 208 return res; 209 } 210 211 @Override 212 public int update(String sql, Object[] params) throws Exception { 213 int tmpRes = generalSqlExecute(sql, params, false, new IPreparedStatementResolve<Integer>() { 214 @Override 215 public Integer solvePreparedStatement(PreparedStatement ps) throws Exception { 216 int tmpRes = ps.executeUpdate(); 217 return tmpRes; 218 } 219 }); 220 return tmpRes; 221 } 222 223 @Override 224 public void beginTransaction() throws Exception { 225 beginTransaction(DEFAULT_TRANSACTION_ISOLATION_LEVEL); 226 } 227 228 @Override 229 public void beginTransaction(int transactionIsolationLevel) throws Exception { 230 Connection conn = getConnection(); 231 conn.setAutoCommit(false); 232 conn.setTransactionIsolation(transactionIsolationLevel); 233 } 234 235 @Override 236 public void commitTransaction() throws Exception { 237 Connection conn = getConnection(); 238 conn.commit(); 239 conn.setAutoCommit(true); 240 releaseConnection(); 241 } 242 243 @Override 244 public void rollbackTransaction() throws Exception { 245 Connection conn = getConnection(); 246 conn.rollback(); 247 conn.setAutoCommit(true); 248 releaseConnection(); 249 } 250 251 }
实现了ISqlExecutor, IManulTransactionSqlExecutor两个接口,这样随便使用哪一个接口均可以。
至此,整个框架已经具有了初步的可用性。
--本文内容到这里就结束了,欢迎指导交流--