package com.shuidi.common.mypool;
import org.apache.log4j.Logger;
import com.shuidi.common.myException.MyException;
import com.shuidi.common.spring.BeanFactory;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
ConnectionManager.java
/**
* jdbc连接管理类
* @Author 李修睿
* @Param
* @return
* 2018-08-15 下午 4:06
**/
public enum ConnectionManager {
/**
* 使用枚举单例对象
* @Author 李修睿
* @Param
* @return
* 2018-08-15 下午 4:07
**/
MANAGER;
private final Logger log = Logger.getLogger(ConnectionManager.class);
/**
* 加载的驱动器名称集合
*/
private Set<String> drivers = new HashSet<String>();
/**
* 数据库连接池字典
* 为每个数据库创建一个连接池(可配置多个数据库)
*/
private ConcurrentHashMap<String, IConnectionPool> pools = new ConcurrentHashMap<String, IConnectionPool>();
private ConnectionManager() {
// createPools();
}
/**
* 装载JDBC驱动程序,并创建连接池
* @throws ClassNotFoundException
*/
private synchronized IConnectionPool createPools(String poolname) throws ClassNotFoundException{
if(pools.containsKey(poolname)){
return pools.get(poolname);
}
DataSource db= (DataSource) BeanFactory.getBean(poolname);
db.setDbName(poolname);
if (db.getUrl() == null) {
log.error(poolname+"数据库的连接字符串为空,请检查配置文件");
//抛出一个异常,说明数据库为空
return null;
}
if (db.getDriverName() == null) {
log.error(poolname+"数据库的driver驱动为空,请检查配置文件");
return null;
}
if (db.getUsername() == null) {
log.error(poolname+"数据库的用户名设置为空,请检查配置文件");
return null;
}
if (db.getPassword() == null) {
log.error(poolname+"数据库的密码设置为空,请检查配置文件");
return null;
}
//验证最小连接数配置正确性
if (db.getMinConnections() <1) {
log.error(poolname+"数据库的最小连接数配置不正确,设置为默认值5");
db.setMinConnections(5);
}
//验证初始连接数配置正确性
if (db.getInitConnections() <db.getMinConnections()) {
log.error(poolname+"数据库的初始连接数配置不正确,设置为最小连接数"+db.getMinConnections());
db.setInitConnections(db.getMinConnections());
}
//验证最大连接数配置正确性
if (db.getMaxConnections() <db.getInitConnections()) {
log.error(poolname+"数据库的最大连接数配置不正确,设置为初始连接数"+db.getInitConnections());
db.setInitConnections(db.getInitConnections());
}
//验证conninterval配置正确性
if (db.getConninterval() <1) {
log.error(poolname+"数据库的等待时间配置不正确,设置为默认值500毫秒");
db.setConninterval(500);
}
//验证timeout配置正确性
if (db.getTimeout() <0) {
log.error(poolname+"数据库的超时重连配置不正确,设置为默认值2000毫秒");
db.setTimeout(2000);
}
//创建驱动
if(!drivers.contains(db.getDriverName())){
try {
Class.forName(db.getDriverName());
log.info("加载JDBC驱动"+db.getDriverName()+"成功");
drivers.add(db.getDriverName());
} catch (ClassNotFoundException e) {
log.error("未找到JDBC驱动" + db.getDriverName() + ",请引入相关包");
throw e;
}
}
log.warn("初始化连接:"+db.getInitConnections());
//创建连接池。这里采用同步方法实现的连接池类ConnectionPool。
//(如果后面我们还有别的实现方式,只需要更改这里就行了。)
IConnectionPool cp = ConnectionPool.createConnectionPool(db);
if (cp.getFreeNum()>0) {
pools.put(poolname, cp);
cp.checkPool();
log.info("创建" + poolname + "数据库连接池成功");
} else {
log.info("创建" + poolname + "数据库连接池失败");
throw new MyException("创建" + poolname + "数据库连接池失败");
}
return cp;
}
/**
* 从指定连接池中获取可用连接
*
* @param poolName 要获取连接的连接池名称
* @throws SQLException
* @return 连接池中的一个可用连接或null
* @throws ClassNotFoundException
*/
public MyConnection getConnection(String poolName) throws SQLException, ClassNotFoundException {
IConnectionPool pool = pools.get(poolName);
if(pool==null){
pool = createPools(poolName);
}
return pool.getCurrentConnection();
}
/**
* 回收指定连接池的连接
*
* @param poolName 连接池名称
* @param conn 要回收的连接
* @throws SQLException
*/
public void closeConnection(String poolName, MyConnection conn) throws SQLException{
IConnectionPool pool = pools.get(poolName);
if (pool != null) {
if(isAutoCommit(conn.getConnection())){//自动提交状态才释放,非自动提交状态可能是开启了事务管理
pool.releaseConn(conn);
}
}else{
log.error("找不到"+poolName+"连接池,无法回收");
throw new MyException("找不到"+poolName+"连接池,无法回收");
}
}
private boolean isAutoCommit(Connection conn) throws SQLException{
boolean b =false;
try {
b = conn.getAutoCommit();
} catch (SQLException e) {
log.error("判断连接是否自动提交出错!");
throw e;
}
return b;
}
/**
* 关闭所有连接,撤销驱动器的注册
*/
public void destroy() {
for (Map.Entry<String, IConnectionPool> poolEntry : pools.entrySet()) {
IConnectionPool pool = poolEntry.getValue();
pool.destroy();
}
log.info("已经关闭所有连接");
}
/**
* 关闭resultSet
* @Author 李修睿
* @Param [rs]
* @return void
* 2018-08-03 上午 9:21
**/
public void closeResultSet(ResultSet rs){
try {
if(null!=rs){
rs.close();
}else{
log.error("ResultSet是null");
}
} catch (SQLException e) {
log.error("关闭ResultSet出错!");
throw new MyException("关闭ResultSet出错!");
}
}
/**
* 关闭statement
* @Author 李修睿
* @Param [stm]
* @return void
* 2018-08-03 上午 9:20
* @throws SQLException
**/
public void closeStatement(Statement stm) throws SQLException {
try {
if(null!=stm){
stm.close();
}else{
log.error("关闭Statement出错!Statement是null");
throw new MyException("关闭Statement出错!Statement是null");
}
} catch (SQLException e) {
log.error("关闭ResultSet出错!");
throw e;
}
}
}
ConnectionPool.java
package com.shuidi.common.mypool;
import org.apache.log4j.Logger;
import com.shuidi.common.myException.DBException;
import java.sql.*;
import java.util.LinkedList;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 类说明 :友元类,包内可见,不提供给客户程序直接访问。
*/
class ConnectionPool implements IConnectionPool {
private static final Logger log = Logger.getLogger(ConnectionPool.class);
/**
* 最长空闲时间,超过就要校验连接是否可用
* @Author 李修睿
* @Param
* @return
* 2018-08-06 下午 1:59
**/
private static final long FREE_TIME = 18000000;
private DataSource propertyBean=null;
/**
* 连接池可用状态
* @Author 李修睿
* @Param
* @return
* 2018-08-06 上午 10:39
**/
private Boolean isActive = true;
/**
* 空闲连接池 。由于List读写频繁,使用LinkedList存储比较合适
* @Author 李修睿
* @Param
* @return
* 2018-08-06 上午 10:39
**/
private LinkedList<MyConnection> freeConnections = new LinkedList<>();
/**
* 活动连接池。活动连接数 <= 允许最大连接数(maxConnections)
* @Author 李修睿
* @Param
* @return
* 2018-08-06 上午 10:39
**/
private LinkedList<MyConnection> activeConnections = new LinkedList<>();
/**
* 当前线程获得的连接
* @Author 李修睿
* @Param
* @return
* 2018-08-06 上午 10:39
**/
private ThreadLocal<MyConnection> currentConnection= new ThreadLocal<>();
/**
* 构造方法无法返回null,所以取消掉。在下面增加了CreateConnectionPool静态方法。
* @Author 李修睿
* @Param
* @return
* 2018-08-06 上午 10:40
**/
private ConnectionPool(){
super();
}
public static ConnectionPool createConnectionPool(DataSource propertyBean) {
ConnectionPool connpool=new ConnectionPool();
connpool.propertyBean = propertyBean;
//基本点2、始使化时根据配置中的初始连接数创建指定数量的连接
for (int i = 0; i < connpool.propertyBean.getInitConnections(); i++) {
Connection con = connpool.newConnection();
if (con!=null){
MyConnection conn = new MyConnection(con) ;
connpool.freeConnections.add(conn);
}
}
connpool.isActive = true;
return connpool;
}
/**
* 检测连接是否有效
* @param conn 数据库连接对象
* @return Boolean
*/
private Boolean isValidConnection(Connection conn){
try {
if(conn==null || conn.isClosed()){
return false;
}
} catch (SQLException e) {
log.error("检测连接出错"+e.getMessage(),e);
return false;
}
return true;
}
/**
* 创建一个新的连接
* @return 数据库连接对象
*/
private Connection newConnection(){
Connection conn = null;
try {
if (this.propertyBean != null) {
conn = DriverManager.getConnection(this.propertyBean.getUrl(),
this.propertyBean.getUsername(),
this.propertyBean.getPassword());
}
} catch (SQLException e) {
log.error(this.propertyBean.getDbName()+"创建新连接出错!"+e.getMessage(),e);
throw new DBException("创建新连接出错!",e);
}
return conn;
}
private synchronized MyConnection getConnection() {
MyConnection conn;
if (this.getActiveNum() < this.propertyBean.getMaxConnections()) {
// 分支1:当前使用的连接没有达到最大连接数
// 基本点3、在连接池没有达到最大连接数之前,如果有可用的空闲连接就直接使用空闲连接,如果没有,就创建新的连接。
if (this.getFreeNum() > 0) {
// 分支1.1:如果空闲池中有连接,就从空闲池中直接获取
log.info("分支1.1:如果空闲池中有连接,就从空闲池中直接获取");
conn = this.freeConnections.pollFirst();
//连接闲置久了也会超时,因此空闲池中的有效连接会越来越少,需要另一个进程进行扫描监测,不断保持一定数量的可用连接。
//在下面定义了checkFreepools的TimerTask类,在checkPool()方法中进行调用。
//基本点5、由于数据库连接闲置久了会超时关闭,因此需要连接池采用机制保证每次请求的连接都是有效可用的。
if(this.isValidConnection(conn.getConnection())){
//闲置小于5个小时,不检测 能否连接上
long now = System.currentTimeMillis();
if((now - conn.getRefreshTime()) < FREE_TIME){
this.activeConnections.add(conn);
currentConnection.set(conn);
//刷新使用时间
conn.setRefreshTime(now);
}else{//闲置大于5小时
if(testConn(conn.getConnection())){
//能连上
this.activeConnections.add(conn);
currentConnection.set(conn);
conn.setRefreshTime(now);
}else{
//连接不上
Connection con=conn.getConnection();
try {
con.close();
} catch (SQLException e) {
log.error("关闭连接出错!"+e.getMessage());
e.printStackTrace();
}
conn.setConnection(this.newConnection());
conn.setRefreshTime(now);
}
}
}else{
//如果连接不可用
//同步方法是可重入锁
conn = getCurrentConnection();
}
} else {
// 分支1.2:如果空闲池中无可用连接,就创建新的连接
log.info("分支1.2:如果空闲池中无可用连接,就创建新的连接");
conn = new MyConnection(newConnection());
this.activeConnections.add(conn);
}
} else {
// 分支2:当前已到达最大连接数
// 基本点4、当连接池中的活动连接数达到最大连接数,新的请求进入等待状态,直到有连接被释放。
log.info("分支2:当前已到达最大连接数 ");
long startTime = System.currentTimeMillis();
//进入等待状态。等待被notify(),notifyALL()唤醒或者超时自动苏醒
try{
this.wait(this.propertyBean.getConninterval());
}catch(InterruptedException e) {
log.error("线程等待被打断");
}
//若线程超时前被唤醒并成功获取连接,就不会走到return null。
//若线程超时前没有获取连接,则返回null。
//如果timeout设置为0,就无限重连。
if(this.propertyBean.getTimeout()!=0){
if(System.currentTimeMillis() - startTime > this.propertyBean.getTimeout()) {
return null;
}
}
conn = this.getConnection();
}
return conn;
}
@Override
public MyConnection getCurrentConnection() {
MyConnection conn=currentConnection.get();
if(null==conn || !isValidConnection(conn.getConnection())){
conn=this.getConnection();
}
return conn;
}
@Override
public synchronized void releaseConn(MyConnection conn){
log.info(Thread.currentThread().getName()+"关闭连接:activeConnections.remove:"+conn.getConnection());
this.activeConnections.remove(conn);
this.currentConnection.remove();
//活动连接池删除的连接,相应的加到空闲连接池中
if(isValidConnection(conn.getConnection())){
freeConnections.add(conn);
}else{
freeConnections.add(new MyConnection(this.newConnection()));
}
//唤醒getConnection()中等待的线程
this.notifyAll();
}
@Override
public synchronized void destroy() {
for (MyConnection conn : this.freeConnections) {
try {
if (this.isValidConnection(conn.getConnection())) {
conn.getConnection().close();
//释放掉连接
}
} catch (SQLException e) {
e.printStackTrace();
}
}
for (MyConnection conn : this.activeConnections) {
try {
if (this.isValidConnection(conn.getConnection())) {
conn.getConnection().close();
//释放掉连接
}
} catch (SQLException e) {
e.printStackTrace();
}
}
this.isActive = false;
this.freeConnections.clear();
this.activeConnections.clear();
}
@Override
public boolean isActive() {
return this.isActive;
}
@Override
public void checkPool() {
ScheduledExecutorService ses=Executors.newScheduledThreadPool(1);
//功能一:开启一个定时器线程输出状态
ses.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
//当活跃连接数较少时 ,空余连接数较多时关闭空余连接释放资源
if(getActiveNum()<propertyBean.getInitConnections()){
if(getFreeNum()>propertyBean.getInitConnections()){
MyConnection conn= freeConnections.pollLast();
if(conn!=null){
try {
conn.getConnection().close();
log.warn("当前空余连接"+getFreeNum()+"个,删除一个空余连接...");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
}, 5, 5, TimeUnit.SECONDS);
//功能二:开启一个定时器线程,监测并维持空闲池中的最小连接数
//代码已维护,永远不会小于最小
// ses.scheduleAtFixedRate(new checkFreepools(this), 1, 5, TimeUnit.SECONDS);
}
@Override
public synchronized int getActiveNum() {
return this.activeConnections.size();
}
@Override
public synchronized int getFreeNum() {
return this.freeConnections.size();
}
static class checkFreepools extends TimerTask {
private ConnectionPool conpool = null;
public checkFreepools(ConnectionPool cp) {
this.conpool = cp;
}
@Override
public void run() {
if (this.conpool != null && this.conpool.isActive()) {
int poolstotalnum = conpool.getFreeNum()
+ conpool.getActiveNum();
int subnum = conpool.propertyBean.getMinConnections()
- poolstotalnum;
if (subnum > 0) {
log.warn(conpool.propertyBean.getDbName()
+ "扫描并维持空闲池中的最小连接数,需补充" + subnum + "个连接");
for (int i = 0; i < subnum; i++) {
conpool.freeConnections.add(new MyConnection(this.conpool.newConnection()));
}
}
}
}
}
/**
*
* @Author 李修睿
* @Param
* @return
* 2018-08-06 下午 2:03
**/
@Override
public boolean testConn(Connection conn) {
String sql = "select 1 from dual";
PreparedStatement pstmt=null;
ResultSet resultSet=null;
try {
pstmt = conn.prepareStatement(sql);
resultSet =pstmt.executeQuery();
} catch (SQLException e) {
log.error("连接数据库"+this.propertyBean.getDbName()+"失败!"+e.getMessage());
return false;
}finally{
try {
if(pstmt!=null) {
pstmt.close();
}
if(resultSet!=null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return true;
}
}
DataBaseExecutor.java
package com.shuidi.common.mypool;
import org.apache.log4j.Logger;
import com.shuidi.common.myException.ParamIsNullException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Administrator
*/
public class DataBaseExecutor {
private static final Logger log = Logger.getLogger(DataBaseExecutor.class);
/**
* 查询操作
* @Author 李修睿
* @Param [sql, poolName, params]
* @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
* 2018-08-16 上午 10:08
* @throws SQLException
* @throws ClassNotFoundException
**/
public static List<Map<String, Object>> executorQuery(String sql, String poolName, Object[] params) throws SQLException, ClassNotFoundException{
if(sql==null||sql.trim()==""){
throw new ParamIsNullException("sql");
}
if(poolName==null||poolName.trim()==""){
throw new ParamIsNullException("poolName");
}
ResultSet rs=null;
List<Map<String, Object>> mapList = new ArrayList<>();
MyConnection conn=null;
//使用预处理防止sql注入
PreparedStatement preparedStatement =null;
try {
conn = ConnectionManager.MANAGER.getConnection(poolName);
preparedStatement = conn.getConnection().prepareStatement(sql);
if (params!=null&¶ms.length>0) {
for (int i=0;i<params.length;i++) {preparedStatement.setObject(i + 1, params[i]);}
}
rs = preparedStatement.executeQuery();
while (rs.next()) {
Map<String,Object> map= new HashMap<>();
ResultSetMetaData md = rs.getMetaData();
int size = md.getColumnCount();
for (int i = 0; i <size; i++) {
map.put((md.getColumnLabel(i+1)).toLowerCase(),rs.getObject(i+1));
}
mapList.add(map);
}
} catch (SQLException e) {
String s= preparedStatement.toString();
String rsql = s.substring(s.indexOf(":")+1);
log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
throw e;
} finally {
ConnectionManager.MANAGER.closeResultSet(rs);
ConnectionManager.MANAGER.closeStatement(preparedStatement);
ConnectionManager.MANAGER.closeConnection(poolName,conn);
}
return mapList;
}
/**
* 、插入、删除、更新操作
* @Author 李修睿
* @Param [sql, poolname, params]
* @return int
* 2018-08-16 上午 10:08
* @throws SQLException
* @throws ClassNotFoundException
**/
public static int executorUpdate(String sql, String poolname,Object[] params) throws SQLException, ClassNotFoundException{
if(sql==null||sql.trim()==""){
throw new ParamIsNullException("sql");
}
if(poolname==null||poolname.trim()==""){
throw new ParamIsNullException("poolName");
}
MyConnection conn=null;
PreparedStatement preparedStatement =null;
int res =0;
try {
conn = ConnectionManager.MANAGER.getConnection(poolname);
preparedStatement = conn.getConnection().prepareStatement(sql);
if (params!=null&¶ms.length>0) {
for (int i=0;i<params.length;i++) {
preparedStatement.setObject(i+1, params[i]);
}
}
res = preparedStatement.executeUpdate();
;
} catch (SQLException e) {
String s= preparedStatement.toString();
String rsql = s.substring(s.indexOf(":")+1);
log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
throw e;
} finally{
ConnectionManager.MANAGER.closeStatement(preparedStatement);
ConnectionManager.MANAGER.closeConnection(poolname,conn);
}
return res;
}
/**
* 批量处理
* @Author 李修睿
* @Param [sql, poolname, params]
* @return int
* 2018-08-16 上午 10:22
* @throws SQLException
* @throws ClassNotFoundException
**/
public static int executorBatch(String sql, String poolname,List<Object[]> params) throws SQLException, ClassNotFoundException{
if(sql==null||sql.trim()==""){
throw new ParamIsNullException("sql");
}
if(poolname==null||poolname.trim()==""){
throw new ParamIsNullException("poolName");
}
MyConnection conn=null;
PreparedStatement preparedStatement =null;
int res = 0;
try {
conn = ConnectionManager.MANAGER.getConnection(poolname);
preparedStatement = conn.getConnection().prepareStatement(sql);
if (params!=null&¶ms.size()>0) {
for (Object [] pars:params) {
for (int j=0, length =pars.length;j<length;j++) {
preparedStatement.setObject(j + 1,pars[j]);
}
preparedStatement.addBatch();
}
}
int[] result= preparedStatement.executeBatch();
if(result==null || (result!=null && result.length==0) ){
return res;
}
for (int re:result) {
res+=re;
}
} catch (SQLException e) {
String s= preparedStatement.toString();
String rsql = s.substring(s.indexOf(":")+1);
log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
throw e;
} finally{
ConnectionManager.MANAGER.closeStatement(preparedStatement);
ConnectionManager.MANAGER.closeConnection(poolname,conn);
}
return res;
}
}
package com.shuidi.common.mypool;
import org.apache.log4j.Logger;
import com.shuidi.common.myException.ParamIsNullException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Administrator
*/
public class DataBaseExecutor {
private static final Logger log = Logger.getLogger(DataBaseExecutor.class);
/**
* 查询操作
* @Author 李修睿
* @Param [sql, poolName, params]
* @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
* 2018-08-16 上午 10:08
* @throws SQLException
* @throws ClassNotFoundException
**/
public static List<Map<String, Object>> executorQuery(String sql, String poolName, Object[] params) throws SQLException, ClassNotFoundException{
if(sql==null||sql.trim()==""){
throw new ParamIsNullException("sql");
}
if(poolName==null||poolName.trim()==""){
throw new ParamIsNullException("poolName");
}
ResultSet rs=null;
List<Map<String, Object>> mapList = new ArrayList<>();
MyConnection conn=null;
//使用预处理防止sql注入
PreparedStatement preparedStatement =null;
try {
conn = ConnectionManager.MANAGER.getConnection(poolName);
preparedStatement = conn.getConnection().prepareStatement(sql);
if (params!=null&¶ms.length>0) {
for (int i=0;i<params.length;i++) {preparedStatement.setObject(i + 1, params[i]);}
}
rs = preparedStatement.executeQuery();
while (rs.next()) {
Map<String,Object> map= new HashMap<>();
ResultSetMetaData md = rs.getMetaData();
int size = md.getColumnCount();
for (int i = 0; i <size; i++) {
map.put((md.getColumnLabel(i+1)).toLowerCase(),rs.getObject(i+1));
}
mapList.add(map);
}
} catch (SQLException e) {
String s= preparedStatement.toString();
String rsql = s.substring(s.indexOf(":")+1);
log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
throw e;
} finally {
ConnectionManager.MANAGER.closeResultSet(rs);
ConnectionManager.MANAGER.closeStatement(preparedStatement);
ConnectionManager.MANAGER.closeConnection(poolName,conn);
}
return mapList;
}
/**
* 、插入、删除、更新操作
* @Author 李修睿
* @Param [sql, poolname, params]
* @return int
* 2018-08-16 上午 10:08
* @throws SQLException
* @throws ClassNotFoundException
**/
public static int executorUpdate(String sql, String poolname,Object[] params) throws SQLException, ClassNotFoundException{
if(sql==null||sql.trim()==""){
throw new ParamIsNullException("sql");
}
if(poolname==null||poolname.trim()==""){
throw new ParamIsNullException("poolName");
}
MyConnection conn=null;
PreparedStatement preparedStatement =null;
int res =0;
try {
conn = ConnectionManager.MANAGER.getConnection(poolname);
preparedStatement = conn.getConnection().prepareStatement(sql);
if (params!=null&¶ms.length>0) {
for (int i=0;i<params.length;i++) {
preparedStatement.setObject(i+1, params[i]);
}
}
res = preparedStatement.executeUpdate();
;
} catch (SQLException e) {
String s= preparedStatement.toString();
String rsql = s.substring(s.indexOf(":")+1);
log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
throw e;
} finally{
ConnectionManager.MANAGER.closeStatement(preparedStatement);
ConnectionManager.MANAGER.closeConnection(poolname,conn);
}
return res;
}
/**
* 批量处理
* @Author 李修睿
* @Param [sql, poolname, params]
* @return int
* 2018-08-16 上午 10:22
* @throws SQLException
* @throws ClassNotFoundException
**/
public static int executorBatch(String sql, String poolname,List<Object[]> params) throws SQLException, ClassNotFoundException{
if(sql==null||sql.trim()==""){
throw new ParamIsNullException("sql");
}
if(poolname==null||poolname.trim()==""){
throw new ParamIsNullException("poolName");
}
MyConnection conn=null;
PreparedStatement preparedStatement =null;
int res = 0;
try {
conn = ConnectionManager.MANAGER.getConnection(poolname);
preparedStatement = conn.getConnection().prepareStatement(sql);
if (params!=null&¶ms.size()>0) {
for (Object [] pars:params) {
for (int j=0, length =pars.length;j<length;j++) {
preparedStatement.setObject(j + 1,pars[j]);
}
preparedStatement.addBatch();
}
}
int[] result= preparedStatement.executeBatch();
if(result==null || (result!=null && result.length==0) ){
return res;
}
for (int re:result) {
res+=re;
}
} catch (SQLException e) {
String s= preparedStatement.toString();
String rsql = s.substring(s.indexOf(":")+1);
log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
throw e;
} finally{
ConnectionManager.MANAGER.closeStatement(preparedStatement);
ConnectionManager.MANAGER.closeConnection(poolname,conn);
}
return res;
}
}
package com.shuidi.common.mypool;
public class DataSource {
private String dbName;
//数据连接驱动
private String driverName;
//数据连接url
private String url;
//数据连接username
private String username;
//数据连接密码
private String password;
//连接池最大连接数
private int maxConnections ;
//连接池最小连接数
private int minConnections;
//连接池初始连接数
private int initConnections;
//重连间隔时间 ,单位毫秒
private int conninterval ;
//获取连接超时时间 ,单位毫秒,0永不超时
private int timeout ;
//构造方法
public DataSource(){
super();
}
//下面是getter and setter
/**
* 获取数据库连接节点名称
* @return
*/
public String getDbName() {
return dbName;
}
/**
* 设置数据库连接节点名称
* @param nodeName
*/
public void setDbName(String nodeName) {
this.dbName = nodeName;
}
/**
* 获取数据库驱动
* @return
*/
public String getDriverName() {
return driverName;
}
/**
* 设置数据库驱动
* @param driverName
*/
public void setDriverName(String driverName) {
this.driverName = driverName;
}
/**
* 获取数据库url
* @return
*/
public String getUrl() {
return url;
}
/**
* 设置数据库url
* @param url
*/
public void setUrl(String url) {
this.url = url;
}
/**
* 获取用户名
* @return
*/
public String getUsername() {
return username;
}
/**
* 设置用户名
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取数据库连接密码
* @return
*/
public String getPassword(){
return password;
}
/**
* 设置数据库连接密码
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取最大连接数
* @return
*/
public int getMaxConnections() {
return maxConnections;
}
/**
* 设置最大连接数
* @param maxConnections
*/
public void setMaxConnections(int maxConnections) {
this.maxConnections = maxConnections;
}
/**
* 获取最小连接数(也是数据池初始连接数)
* @return
*/
public int getMinConnections() {
return minConnections;
}
/**
* 设置最小连接数(也是数据池初始连接数)
* @param minConnections
*/
public void setMinConnections(int minConnections) {
this.minConnections = minConnections;
}
/**
* 获取初始加接数
* @return
*/
public int getInitConnections() {
return initConnections;
}
/**
* 设置初始连接数
* @param initConnections
*/
public void setInitConnections(int initConnections) {
this.initConnections = initConnections;
}
/**
* 获取重连间隔时间,单位毫秒
* @return
*/
public int getConninterval() {
return conninterval;
}
/**
* 设置重连间隔时间,单位毫秒
* @param conninterval
*/
public void setConninterval(int conninterval) {
this.conninterval = conninterval;
}
/**
* 获取连接超时时间,单位毫秒
* @return
*/
public int getTimeout() {
return timeout;
}
/**
* 设置连接超时时间 ,单位毫秒,0-无限重连
* @param timeout
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}
IConnectionPool.java
package com.shuidi.common.mypool;
import java.sql.Connection;
import java.sql.SQLException;
public interface IConnectionPool {
/**
* 获得当前线程的连接库连接,如果为空则获取一个空闲的连接,如果等待超时则返回null
* @return 数据库连接对象
*/
public MyConnection getCurrentConnection();
/**
* 释放当前线程数据库连接
* @param conn 数据库连接对象
* @throws SQLException
*/
public void releaseConn(MyConnection conn);
/**
* 销毁清空当前连接池
*/
public void destroy();
/**
* 连接池可用状态
* @return 连接池是否可用
*/
public boolean isActive();
/**
* 定时器,检查连接池
*/
public void checkPool();
/**
* 获取线程池活动连接数
* @return 线程池活动连接数
*/
public int getActiveNum();
/**
* 获取线程池空闲连接数
* @return 线程池空闲连接数
*/
public int getFreeNum();
/**
* 测试连接是否真实可用
* @return
*/
public boolean testConn(Connection conn);
}
MyConnection.java
package com.shuidi.common.mypool;
import java.sql.Connection;
public class MyConnection {
private Connection connection;//连接
private long refreshTime;//刷新时间
public MyConnection(Connection conn){
this.connection = conn;
this.refreshTime = System.currentTimeMillis();
}
public Connection getConnection() {
return connection;
}
public void setConnection(Connection connection) {
this.connection = connection;
}
public long getRefreshTime() {
return refreshTime;
}
public void setRefreshTime(long refreshTime) {
this.refreshTime = refreshTime;
}
}
TransactionAspect.java
package com.shuidi.common.mypool;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import com.shuidi.common.myException.UnKonwException;
import com.shuidi.common.myanotation.Transaction;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
@Aspect
public class TransactionAspect {
private static final Logger log = Logger.getLogger(TransactionAspect.class);
/**
* 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. 使用 @Pointcut 来声明切入点表达式.
* 后面的其他通知直接使用方法名来引用当前的切入点表达式.
*/
@Pointcut("@annotation(com.shuidi.common.myanotation.Transaction)")
public void declareJointPointExpression() {
}
// /**
// * 前置通知
// * 在 com.atguigu.spring.aop.ArithmeticCalculator
// * 接口的每一个实现类的每一个方法开始之前执行一段代码
// * 用通配符*来表示所有
// */
//// @Before("execution(public double
// com.spring2.lee.aop.impl.ArithmeticCalculator.plus(int, int))")
// @Before("declareJointPointExpression()")
// public void beforeMethod(JoinPoint joinPoint) {
// String methodName = joinPoint.getSignature().getName();
// Object[] args = joinPoint.getArgs();
// System.out.println("@Before: before method " + methodName + " begin
// with:" + Arrays.asList(args));
// }
//
// /**
// * 后置通知
// * 在方法执行之后执行的代码. 无论该方法是否出现异常
// * @param joinPoint
// */
//
// @After("declareJointPointExpression()")
// public void afterMethod(JoinPoint joinPoint) {
// String methodName = joinPoint.getSignature().getName();
// Object[] args = joinPoint.getArgs();
// System.out.println("@After:after method " + methodName +
// " end " + Arrays.asList(args));
// }
//
// /**
// * 返回通知
// * 在方法法正常结束受执行的代码
// * 返回通知是可以访问到方法的返回值的!
// */
// @AfterReturning(value = "declareJointPointExpression()",
// returning = "result")
// public void afterReturning(JoinPoint joinPoint,
// Object result) {
// String methodName = joinPoint.getSignature().getName();
// System.out.println(" @AfterReturning:The method " + methodName +
// " ends with " + result);
// }
//
// /**
// * 异常通知
// * 在目标方法出现异常时会执行的代码.
// * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码
// */
// @AfterThrowing(value = "declareJointPointExpression()", throwing = "e")
// public void afterThrowing(JoinPoint joinPoint, Exception e) {
// String methodName = joinPoint.getSignature().getName();
// System.out.println("@AfterThrowing:The method " + methodName +
// " occurs excetion:" + e);
// }
/**
* 环绕通知需要携带 ProceedingJoinPoint 类型的参数. 环绕通知类似于动态代理的全过程: ProceedingJoinPoint
* 类型的参数可以决定是否执行目标方法. 且环绕通知必须有返回值, 返回值即为目标方法的返回值
* @throws SQLException
*/
@Around("declareJointPointExpression()")
public Object aroundMethod(ProceedingJoinPoint pjd) throws SQLException {
Object result = null;
Signature sig = pjd.getSignature();
MethodSignature msig;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
msig = (MethodSignature) sig;
Object target = pjd.getTarget();
MyConnection myconn =null;
Connection conn = null;
String poolname = "";
String className = "";
String methodName = "";
try {
Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
Transaction permission = currentMethod.getAnnotation(Transaction.class);
className = target.getClass().getName();
methodName = currentMethod.getName();
poolname = permission.value();
myconn = ConnectionManager.MANAGER.getConnection(poolname);
conn =myconn.getConnection();
log.warn(className + ":" + methodName + "方法的" + poolname + "连接池启用事务管理");
conn.setAutoCommit(false);
result = pjd.proceed();// 执行方法
conn.commit();
log.warn(className + ":" + methodName + "方法的" + poolname + "连接池提交事务");
} catch (Throwable e) {
result = null;
//ConnectionManager.rollbackTransaction(conn);
try {
if(conn!=null)
conn.rollback();
} catch (SQLException e1) {
log.error(className + ":" + methodName + "方法的连接池执行事务回滚失败",e);
throw e1;
}
log.error(className + ":" + methodName + "方法的" + poolname + "连接池执行事务失败,事务回滚",e);
throw new UnKonwException("事务管理异常!"+e.getMessage());
} finally {
try {
if(conn!=null)
conn.setAutoCommit(true);
} catch (SQLException e) {
log.error(className + ":" + methodName + "方法的"+conn+"设置事务自动提交失败",e);
throw e;
}
log.warn(className + ":" + methodName + "方法的" + poolname + "事物结束,释放连接..");
ConnectionManager.MANAGER.closeConnection(poolname, myconn);
}
return result;
}
}
Transaction.java
package com.shuidi.common.myanotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义事务管理注解
* @author 李修睿
* @date 2018年4月23日 下午1:58:37
*/
@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取
@Target(ElementType.METHOD)//目标是方法
@Documented//文档生成时,该注解将被包含在javadoc中,可去掉
public @interface Transaction {
String value() default "companyadvertisement";
}