All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.dreampie.common.plugin.db.druid.DruidXAPlugin Maven / Gradle / Ivy

There is a newer version: 1.2.2
Show newest version
package cn.dreampie.common.plugin.db.druid;

import cn.dreampie.common.plugin.db.tx.XAXid;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.IPlugin;
import com.jfinal.plugin.activerecord.IDataSourceProvider;

import javax.sql.DataSource;
import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by wangrenhui on 2014/5/9.
 */
public class DruidXAPlugin implements IPlugin, IDataSourceProvider {

  // 基本属性 url、user、password
  private String url;
  private String username;
  private String password;
  private String driverClass = "com.mysql.jdbc.Driver";

  // 初始连接池大小、最小空闲连接数、最大活跃连接数
  private int initialSize = 10;
  private int minIdle = 10;
  private int maxActive = 100;

  // 配置获取连接等待超时的时间
  private long maxWait = DruidXADataSource.DEFAULT_MAX_WAIT;

  // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
  private long timeBetweenEvictionRunsMillis = DruidXADataSource.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
  // 配置连接在池中最小生存的时间
  private long minEvictableIdleTimeMillis = DruidXADataSource.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
  // 配置发生错误时多久重连
  private long timeBetweenConnectErrorMillis = DruidXADataSource.DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS;

  /**
   * hsqldb - "select 1 from INFORMATION_SCHEMA.SYSTEM_USERS"
   * Oracle - "select 1 from dual"
   * DB2 - "select 1 from sysibm.sysdummy1"
   * mysql - "select 1"
   */
  private String validationQuery = "select 1";
  private boolean testWhileIdle = true;
  private boolean testOnBorrow = false;
  private boolean testOnReturn = false;

  // 是否打开连接泄露自动检测
  private boolean removeAbandoned = false;
  // 连接长时间没有使用,被认为发生泄露时长
  private long removeAbandonedTimeoutMillis = 300 * 1000;
  // 发生泄露时是否需要输出 log,建议在开启连接泄露检测时开启,方便排错
  private boolean logAbandoned = false;

  // 是否缓存preparedStatement,即PSCache,对支持游标的数据库性能提升巨大,如 oracle、mysql 5.5 及以上版本
  // private boolean poolPreparedStatements = false;	// oracle、mysql 5.5 及以上版本建议为 true;

  // 只要maxPoolPreparedStatementPerConnectionSize>0,poolPreparedStatements就会被自动设定为true,使用oracle时可以设定此值。
  private int maxPoolPreparedStatementPerConnectionSize = -1;

  // 配置监控统计拦截的filters
  private String filters;    // 监控统计:"stat"    防SQL注入:"wall"     组合使用: "stat,wall"
  private List filterList;

  private DruidXADataSource ds;

  public DruidXAPlugin(String url, String username, String password) {
    this.url = url;
    this.username = username;
    this.password = password;
  }

  public DruidXAPlugin(String url, String username, String password, String driverClass) {
    this.url = url;
    this.username = username;
    this.password = password;
    this.driverClass = driverClass;
  }

  public DruidXAPlugin(String url, String username, String password, String driverClass, String filters) {
    this.url = url;
    this.username = username;
    this.password = password;
    this.driverClass = driverClass;
    this.filters = filters;
  }

  /**
   * 设置过滤器,如果要开启监控统计需要使用此方法或在构造方法中进行设置
   * 

* 监控统计:"stat" * 防SQL注入:"wall" * 组合使用: "stat,wall" *

* * @param filters filters * @return Plugin */ public DruidXAPlugin setFilters(String filters) { this.filters = filters; return this; } public synchronized DruidXAPlugin addFilter(Filter filter) { if (filterList == null) filterList = new ArrayList(); filterList.add(filter); return this; } public boolean start() { ds = new DruidXADataSource(); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); ds.setDriverClassName(driverClass); ds.setInitialSize(initialSize); ds.setMinIdle(minIdle); ds.setMaxActive(maxActive); ds.setMaxWait(maxWait); ds.setTimeBetweenConnectErrorMillis(timeBetweenConnectErrorMillis); ds.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); ds.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); ds.setValidationQuery(validationQuery); ds.setTestWhileIdle(testWhileIdle); ds.setTestOnBorrow(testOnBorrow); ds.setTestOnReturn(testOnReturn); ds.setRemoveAbandoned(removeAbandoned); ds.setRemoveAbandonedTimeoutMillis(removeAbandonedTimeoutMillis); ds.setLogAbandoned(logAbandoned); //只要maxPoolPreparedStatementPerConnectionSize>0,poolPreparedStatements就会被自动设定为true,参照druid的源码 ds.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); if (StrKit.notBlank(filters)) try { ds.setFilters(filters); } catch (SQLException e) { throw new RuntimeException(e); } addFilterList(ds); return true; } private void addFilterList(DruidXADataSource ds) { if (filterList != null) { List targetList = ds.getProxyFilters(); for (Filter add : filterList) { boolean found = false; for (Filter target : targetList) { if (add.getClass().equals(target.getClass())) { found = true; break; } } if (!found) targetList.add(add); } } } public boolean stop() { if (ds != null) ds.close(); return true; } public DataSource getDataSource() { return ds; } public DruidXAPlugin set(int initialSize, int minIdle, int maxActive) { this.initialSize = initialSize; this.minIdle = minIdle; this.maxActive = maxActive; return this; } public DruidXAPlugin setDriverClass(String driverClass) { this.driverClass = driverClass; return this; } public DruidXAPlugin setInitialSize(int initialSize) { this.initialSize = initialSize; return this; } public DruidXAPlugin setMinIdle(int minIdle) { this.minIdle = minIdle; return this; } public DruidXAPlugin setMaxActive(int maxActive) { this.maxActive = maxActive; return this; } public DruidXAPlugin setMaxWait(long maxWait) { this.maxWait = maxWait; return this; } public DruidXAPlugin setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; return this; } public DruidXAPlugin setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; return this; } /** * hsqldb - "select 1 from INFORMATION_SCHEMA.SYSTEM_USERS" * Oracle - "select 1 from dual" * DB2 - "select 1 from sysibm.sysdummy1" * mysql - "select 1" * * @param validationQuery valid * @return Plugin */ public DruidXAPlugin setValidationQuery(String validationQuery) { this.validationQuery = validationQuery; return this; } public DruidXAPlugin setTestWhileIdle(boolean testWhileIdle) { this.testWhileIdle = testWhileIdle; return this; } public DruidXAPlugin setTestOnBorrow(boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; return this; } public DruidXAPlugin setTestOnReturn(boolean testOnReturn) { this.testOnReturn = testOnReturn; return this; } public DruidXAPlugin setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) { this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; return this; } public final void setTimeBetweenConnectErrorMillis(long timeBetweenConnectErrorMillis) { this.timeBetweenConnectErrorMillis = timeBetweenConnectErrorMillis; } public final void setRemoveAbandoned(boolean removeAbandoned) { this.removeAbandoned = removeAbandoned; } public final void setRemoveAbandonedTimeoutMillis(long removeAbandonedTimeoutMillis) { this.removeAbandonedTimeoutMillis = removeAbandonedTimeoutMillis; } public final void setLogAbandoned(boolean logAbandoned) { this.logAbandoned = logAbandoned; } private static DruidXADataSource getDruidXADataSource(String url, String username, String password) { DruidXAPlugin plugin = new DruidXAPlugin(url, username, password); DruidXADataSource ds = new DruidXADataSource(); ds.setUrl(plugin.url); ds.setUsername(plugin.username); ds.setPassword(plugin.password); ds.setDriverClassName(plugin.driverClass); ds.setInitialSize(plugin.initialSize); ds.setMinIdle(plugin.minIdle); ds.setMaxActive(plugin.maxActive); ds.setMaxWait(plugin.maxWait); ds.setTimeBetweenConnectErrorMillis(plugin.timeBetweenConnectErrorMillis); ds.setTimeBetweenEvictionRunsMillis(plugin.timeBetweenEvictionRunsMillis); ds.setMinEvictableIdleTimeMillis(plugin.minEvictableIdleTimeMillis); ds.setValidationQuery(plugin.validationQuery); ds.setTestWhileIdle(plugin.testWhileIdle); ds.setTestOnBorrow(plugin.testOnBorrow); ds.setTestOnReturn(plugin.testOnReturn); ds.setRemoveAbandoned(plugin.removeAbandoned); ds.setRemoveAbandonedTimeoutMillis(plugin.removeAbandonedTimeoutMillis); ds.setLogAbandoned(plugin.logAbandoned); //只要maxPoolPreparedStatementPerConnectionSize>0,poolPreparedStatements就会被自动设定为true,参照druid的源码 ds.setMaxPoolPreparedStatementPerConnectionSize(plugin.maxPoolPreparedStatementPerConnectionSize); if (StrKit.notBlank(plugin.filters)) try { ds.setFilters(plugin.filters); } catch (SQLException e) { throw new RuntimeException(e); } plugin.addFilterList(ds); return ds; } public static void main(String[] args) throws SQLException { //数据库表需要时innodb类型才支持分布式事务 DruidXADataSource ds1 = getDruidXADataSource("jdbc:mysql://192.168.1.211/sm_card?useUnicode=true&characterEncoding=UTF-8", "dev", "dev1010"); DruidXADataSource ds2 = getDruidXADataSource("jdbc:mysql://192.168.1.211/sm_shop_master?useUnicode=true&characterEncoding=UTF-8", "dev", "dev1010"); boolean result = true; XAConnection xaConnection1 = ds1.getXAConnection(); Connection connection1 = xaConnection1.getConnection(); //用事务,必须设置setAutoCommit false,表示手动提交 connection1.setAutoCommit(false); //设置事务的隔离级别。 connection1.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); XAResource xaResource1 = xaConnection1.getXAResource(); Xid xid1 = XAXid.uniqueXid(1); XAConnection xaConnection2 = ds2.getXAConnection(); Connection connection2 = xaConnection2.getConnection(); //用事务,必须设置setAutoCommit false,表示手动提交 connection2.setAutoCommit(false); //设置事务的隔离级别。 connection2.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); XAResource xaResource2 = xaConnection2.getXAResource(); Xid xid2 = XAXid.uniqueXid(1); int result1 = -1; int result2 = -1; try { xaResource1.setTransactionTimeout(0); xaResource1.start(xid1, XAResource.TMNOFLAGS); try { Statement stmt1 = connection1.createStatement(); stmt1.executeUpdate("UPDATE fun_card SET state=0 WHERE id=30000;"); // Commit the transaction. xaResource1.end(xid1, XAResource.TMSUCCESS); } catch (SQLException e) { e.printStackTrace(); xaResource1.end(xid1, XAResource.TMFAIL); result = result && false; } result1 = xaResource1.prepare(xid1); xaResource2.setTransactionTimeout(0); xaResource2.start(xid2, XAResource.TMNOFLAGS); try { Statement stmt2 = connection2.createStatement(); stmt2.executeUpdate("UPDATE com_account_card SET use_count=0 WHERE id=107;"); // Commit the transaction. xaResource2.end(xid2, XAResource.TMSUCCESS); } catch (SQLException e) { e.printStackTrace(); xaResource2.end(xid2, XAResource.TMFAIL); result = result && false; } result2 = xaResource2.prepare(xid2); if (result1 == XAResource.XA_OK && result2 == XAResource.XA_OK) { result = result && true; } } catch (XAException e) { e.printStackTrace(); result = result && false; } finally { try { if (result) { xaResource1.commit(xid1, false); xaResource2.commit(xid2, false); } else { if (result1 == XAResource.XA_OK) xaResource1.rollback(xid1); if (result2 == XAResource.XA_OK) xaResource2.rollback(xid2); } // Cleanup. connection1.close(); xaConnection1.close(); connection2.close(); xaConnection2.close(); } catch (XAException e) { e.printStackTrace(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy