package com.taobao.tddl.group.jdbc;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.taobao.tddl.common.mock.MockDataSource;
import com.taobao.tddl.common.model.DBType;
/**
* @author yangzhu
*/
public class TGroupConnectionTest {
@Before
public void setUp() {
MockDataSource.clearTrace();
}
@Test
public void java_sql_Connection_api_support() throws Exception {
TGroupDataSource ds = new TGroupDataSource();
Connection conn = ds.getConnection();
assertFalse(conn.isClosed());
assertTrue(conn.getAutoCommit());
assertNull(conn.getWarnings());
assertTrue((conn.getMetaData() instanceof TGroupDatabaseMetaData));
assertTrue((conn.createStatement() instanceof TGroupStatement));
assertTrue((conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE) instanceof TGroupStatement));
assertTrue((conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE,
ResultSet.HOLD_CURSORS_OVER_COMMIT) instanceof TGroupStatement));
assertTrue((conn.prepareStatement("sql") instanceof TGroupPreparedStatement));
assertTrue((conn.prepareStatement("sql", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE) instanceof TGroupPreparedStatement));
assertTrue((conn.prepareStatement("sql",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE,
ResultSet.HOLD_CURSORS_OVER_COMMIT) instanceof TGroupPreparedStatement));
assertTrue((conn.prepareStatement("sql", Statement.RETURN_GENERATED_KEYS) instanceof TGroupPreparedStatement));
assertTrue((conn.prepareStatement("sql", new int[0]) instanceof TGroupPreparedStatement));
assertTrue((conn.prepareStatement("sql", new String[0]) instanceof TGroupPreparedStatement));
// assertTrue((conn.prepareCall("sql") instanceof
// TGroupCallableStatement));
// assertTrue((conn.prepareCall("sql",
// ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)
// instanceof TGroupCallableStatement));
// assertTrue((conn.prepareCall("sql",
// ResultSet.TYPE_SCROLL_INSENSITIVE,
// ResultSet.CONCUR_UPDATABLE,
// ResultSet.HOLD_CURSORS_OVER_COMMIT) instanceof
// TGroupCallableStatement));
}
@Test
public void test_一个连接上创建两个Statement() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "rw", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
db1.setClosed(true);
db2.setClosed(false);
// 链接一旦选定就会保持所选择的库,直到close
conn = tgds.getConnection();
stat = conn.createStatement();
stat.executeQuery("select 1 from test");
MockDataSource.showTrace();
Assert.assertTrue(MockDataSource.hasTrace("db", "db2", "select 1 from test"));
db1.setClosed(false);
db2.setClosed(true);
stat = conn.createStatement();
stat.executeQuery("select 2 from test");
// Assert.assertTrue(MockDataSource.hasTrace("db", "db1",
// "select 1 from test"));
Assert.fail("没有重用第一个连接");
} catch (SQLException e) {
// Assert.fail(ExceptionUtils.getFullStackTrace(e));
System.out.println(e.getMessage());
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
}
@Test
public void test_创建Statement失败重试_读请求() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "rw", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
MockDataSource.addPreException(MockDataSource.m_createStatement, db1.genFatalSQLException());
stat.executeQuery("select 1 from test");
MockDataSource.showTrace();
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "getConnection"));
// 会在db2做重试
Assert.assertTrue(MockDataSource.hasMethod("db", "db2", "getConnection"));
} catch (SQLException e) {
Assert.fail(ExceptionUtils.getFullStackTrace(e));
// System.out.println(e.getMessage());
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
}
@Test
public void test_创建Statement失败不重试_写请求() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "rw", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
MockDataSource.addPreException(MockDataSource.m_createStatement, db1.genFatalSQLException());
stat.executeQuery("update test set name = 'newname'");
} catch (SQLException e) {
// Assert.fail(ExceptionUtils.getFullStackTrace(e));
System.out.println(e.getMessage());
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "getConnection"));
// 写操作不会在db2做重试
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "getConnection"));
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
}
@Test
public void test_autocommit() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "w", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
stat.executeQuery("select 1 from test");
conn.setAutoCommit(false);
stat.executeUpdate("update t set name='newName'");
conn.commit();
} catch (SQLException e) {
Assert.fail(ExceptionUtils.getFullStackTrace(e));
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
MockDataSource.showTrace();
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db2", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "setAutoCommit"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "rollback"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "setAutoCommit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "rollback"));
}
@Test
public void test_no_trans() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "w", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
stat.executeQuery("select 1 from test");
} catch (SQLException e) {
Assert.fail(ExceptionUtils.getFullStackTrace(e));
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
MockDataSource.showTrace();
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db2", "getConnection"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "setAutoCommit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "rollback"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "setAutoCommit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "rollback"));
}
@Test
public void test_write_trans() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "w", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
conn.setAutoCommit(false);
stat.executeUpdate("update t set name='newName'");
conn.commit();
} catch (SQLException e) {
Assert.fail(ExceptionUtils.getFullStackTrace(e));
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
MockDataSource.showTrace();
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "getConnection"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "setAutoCommit"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "rollback"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "setAutoCommit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "rollback"));
}
@Test
public void test_read_trans() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "w", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
conn.setAutoCommit(false);
stat.executeQuery("select 1 from test");
conn.commit();
} catch (SQLException e) {
Assert.fail(ExceptionUtils.getFullStackTrace(e));
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
MockDataSource.showTrace();
// 如果是事务读,强制选择了写库
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "getConnection"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "setAutoCommit"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "rollback"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "setAutoCommit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "rollback"));
}
@Test
public void test_write_and_read_trans() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "w", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
conn.setAutoCommit(false);
stat.executeQuery("update t set name='newName'");
stat.executeQuery("select 1 from test");
conn.commit();
} catch (SQLException e) {
Assert.fail(ExceptionUtils.getFullStackTrace(e));
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
MockDataSource.showTrace();
// 事务中的读请求,选择写库
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "getConnection"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "setAutoCommit"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "rollback"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "setAutoCommit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "rollback"));
}
@Test
public void test_read_and_write_trans() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "w", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
conn.setAutoCommit(false);
stat.executeQuery("select 1 from test");
stat.executeQuery("update t set name='newName'");
conn.commit();
} catch (SQLException e) {
Assert.fail(ExceptionUtils.getFullStackTrace(e));
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
MockDataSource.showTrace();
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "getConnection"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "setAutoCommit"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "rollback"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "setAutoCommit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "rollback"));
}
@Test
public void test_read_untrans_write_trans() {
TGroupDataSource tgds = new TGroupDataSource();
tgds.setDbGroupKey("dbKey0");
List<DataSourceWrapper> dataSourceWrappers = new ArrayList<DataSourceWrapper>();
MockDataSource db1 = new MockDataSource("db", "db1");
MockDataSource db2 = new MockDataSource("db", "db2");
DataSourceWrapper dsw1 = new DataSourceWrapper("db1", "w", db1, DBType.MYSQL);
DataSourceWrapper dsw2 = new DataSourceWrapper("db2", "r", db2, DBType.MYSQL);
dataSourceWrappers.add(dsw1);
dataSourceWrappers.add(dsw2);
tgds.init(dataSourceWrappers);
TGroupConnection conn = null;
Statement stat = null;
try {
conn = tgds.getConnection();
stat = conn.createStatement();
stat.executeQuery("select 1 from test");
conn.setAutoCommit(false);
stat.executeQuery("update t set name='newName'");
conn.commit();
} catch (SQLException e) {
Assert.fail(ExceptionUtils.getFullStackTrace(e));
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
}
}
}
}
MockDataSource.showTrace();
// 刚开始读不处于事务中,选择读请求
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db2", "getConnection"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "setAutoCommit"));
Assert.assertTrue(MockDataSource.hasMethod("db", "db1", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db1", "rollback"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "setAutoCommit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "commit"));
Assert.assertFalse(MockDataSource.hasMethod("db", "db2", "rollback"));
}
}