org.redkale.source.DataJdbcSource Maven / Gradle / Ivy
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.source;
import java.io.Serializable;
import java.net.URL;
import java.sql.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.logging.Level;
import org.redkale.service.Local;
import org.redkale.util.*;
/**
* DataSource的JDBC实现类
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Local
@AutoLoad(false)
@SuppressWarnings("unchecked")
@ResourceType(DataSource.class)
public class DataJdbcSource extends DataSqlSource {
public DataJdbcSource(String unitName, URL persistxml, Properties readprop, Properties writeprop) {
super(unitName, persistxml, readprop, writeprop);
}
@Override
protected final String prepareParamSign(int index) {
return "?";
}
@Override
protected final boolean isAsync() {
return false;
}
@Override
protected PoolSource createPoolSource(DataSource source, String rwtype, ArrayBlockingQueue queue, Semaphore semaphore, Properties prop) {
return new PoolJdbcSource(this.name, this.persistxml, rwtype, queue, semaphore, prop, this.logger);
}
@Override
protected CompletableFuture insertDB(EntityInfo info, T... values) {
Connection conn = null;
try {
int c = 0;
conn = writePool.poll();
final String sql = info.getInsertPrepareSQL(values[0]);
final Class primaryType = info.getPrimary().type();
final Attribute primary = info.getPrimary();
Attribute[] attrs = info.insertAttributes;
conn.setReadOnly(false);
conn.setAutoCommit(true);
PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, values);
try {
int[] cs = prestmt.executeBatch();
int c1 = 0;
for (int cc : cs) {
c1 += cc;
}
c = c1;
} catch (SQLException se) {
if (info.tableStrategy == null || !info.isTableNotExist(se)) throw se;
synchronized (info.tables) {
final String oldTable = info.table;
final String newTable = info.getTable(values[0]);
if (!info.tables.contains(newTable)) {
try {
Statement st = conn.createStatement();
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
st.close();
info.tables.add(newTable);
} catch (SQLException sqle) { //多进程并发时可能会出现重复建表
if (newTable.indexOf('.') > 0 && info.isTableNotExist(se)) {
Statement st;
try {
st = conn.createStatement();
st.execute("CREATE DATABASE " + newTable.substring(0, newTable.indexOf('.')));
st.close();
} catch (SQLException sqle1) {
logger.log(Level.SEVERE, "create database(" + newTable.substring(0, newTable.indexOf('.')) + ") error", sqle1);
}
try {
st = conn.createStatement();
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
st.close();
info.tables.add(newTable);
} catch (SQLException sqle2) {
logger.log(Level.SEVERE, "create table2(" + info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable) + ") error", sqle2);
}
} else {
logger.log(Level.SEVERE, "create table(" + info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable) + ") error", sqle);
}
}
}
}
prestmt.close();
prestmt = createInsertPreparedStatement(conn, sql, info, values);
int[] cs = prestmt.executeBatch();
int c1 = 0;
for (int cc : cs) {
c1 += cc;
}
c = c1;
}
if (info.autoGenerated) { //由数据库自动生成主键值
ResultSet set = prestmt.getGeneratedKeys();
int i = -1;
while (set.next()) {
if (primaryType == int.class) {
primary.set(values[++i], set.getInt(1));
} else if (primaryType == long.class) {
primary.set(values[++i], set.getLong(1));
} else {
primary.set(values[++i], set.getObject(1));
}
}
set.close();
}
prestmt.close();
//------------------------------------------------------------
if (info.isLoggable(logger, Level.FINEST)) { //打印调试信息
char[] sqlchars = sql.toCharArray();
for (final T value : values) {
//-----------------------------
StringBuilder sb = new StringBuilder(128);
int i = 0;
for (char ch : sqlchars) {
if (ch == '?') {
Object obj = attrs[i++].get(value);
if (obj != null && obj.getClass().isArray()) {
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
} else {
sb.append(FilterNode.formatToString(obj));
}
} else {
sb.append(ch);
}
}
String debugsql = sb.toString();
if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " insert sql=" + debugsql.replaceAll("(\r|\n)", "\\n"));
}
} //打印结束
return CompletableFuture.completedFuture(c);
} catch (SQLException e) {
CompletableFuture future = new CompletableFuture();
future.completeExceptionally(e);
return future;
} finally {
if (conn != null) writePool.offerConnection(conn);
}
}
protected PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql,
final EntityInfo info, T... values) throws SQLException {
Attribute[] attrs = info.insertAttributes;
final PreparedStatement prestmt = info.autoGenerated ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
for (final T value : values) {
int i = 0;
if (info.autouuid) info.createPrimaryValue(value);
for (Attribute attr : attrs) {
Serializable val = attr.get(value);
if (val instanceof byte[]) {
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) val);
prestmt.setObject(++i, blob);
} else if (val instanceof AtomicInteger) {
prestmt.setObject(++i, ((AtomicInteger) val).get());
} else if (val instanceof AtomicLong) {
prestmt.setObject(++i, ((AtomicLong) val).get());
} else {
prestmt.setObject(++i, val);
}
}
prestmt.addBatch();
}
return prestmt;
}
@Override
protected CompletableFuture deleteDB(EntityInfo info, Flipper flipper, String sql) {
Connection conn = null;
try {
conn = writePool.poll();
conn.setReadOnly(false);
conn.setAutoCommit(true);
sql += ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit()));
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
final Statement stmt = conn.createStatement();
int c = stmt.executeUpdate(sql);
stmt.close();
return CompletableFuture.completedFuture(c);
} catch (SQLException e) {
CompletableFuture future = new CompletableFuture();
future.completeExceptionally(e);
return future;
} finally {
if (conn != null) writePool.offerConnection(conn);
}
}
@Override
protected CompletableFuture updateDB(EntityInfo info, T... values) {
Connection conn = null;
try {
conn = writePool.poll();
conn.setReadOnly(false);
conn.setAutoCommit(true);
final String updateSQL = info.getUpdatePrepareSQL(values[0]);
final PreparedStatement prestmt = conn.prepareStatement(updateSQL);
Attribute[] attrs = info.updateAttributes;
final boolean debugfinest = info.isLoggable(logger, Level.FINEST);
char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null;
final Attribute primary = info.getPrimary();
for (final T value : values) {
int k = 0;
for (Attribute attr : attrs) {
Serializable val = attr.get(value);
if (val instanceof byte[]) {
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) val);
prestmt.setObject(++k, blob);
} else if (val instanceof AtomicInteger) {
prestmt.setObject(++k, ((AtomicInteger) val).get());
} else if (val instanceof AtomicLong) {
prestmt.setObject(++k, ((AtomicLong) val).get());
} else {
prestmt.setObject(++k, val);
}
}
prestmt.setObject(++k, primary.get(value));
prestmt.addBatch();//------------------------------------------------------------
if (debugfinest) { //打印调试信息
//-----------------------------
int i = 0;
StringBuilder sb = new StringBuilder(128);
for (char ch : sqlchars) {
if (ch == '?') {
Object obj = i == attrs.length ? primary.get(value) : attrs[i++].get(value);
if (obj != null && obj.getClass().isArray()) {
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
} else {
sb.append(FilterNode.formatToString(obj));
}
} else {
sb.append(ch);
}
}
String debugsql = sb.toString();
if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " update sql=" + debugsql.replaceAll("(\r|\n)", "\\n"));
} //打印结束
}
int[] pc = prestmt.executeBatch();
int c = 0;
for (int p : pc) {
if (p >= 0) c += p;
}
prestmt.close();
return CompletableFuture.completedFuture(c);
} catch (SQLException e) {
CompletableFuture future = new CompletableFuture();
future.completeExceptionally(e);
return future;
} finally {
if (conn != null) writePool.offerConnection(conn);
}
}
@Override
protected CompletableFuture updateDB(EntityInfo info, Flipper flipper, String sql, boolean prepared, Object... params) {
Connection conn = null;
try {
conn = writePool.poll();
conn.setReadOnly(false);
conn.setAutoCommit(true);
if (prepared) {
final PreparedStatement prestmt = conn.prepareStatement(sql);
int index = 0;
for (Object param : params) {
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) param);
prestmt.setBlob(++index, blob);
}
int c = prestmt.executeUpdate();
prestmt.close();
return CompletableFuture.completedFuture(c);
} else {
if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
final Statement stmt = conn.createStatement();
int c = stmt.executeUpdate(sql);
stmt.close();
return CompletableFuture.completedFuture(c);
}
} catch (SQLException e) {
CompletableFuture future = new CompletableFuture();
future.completeExceptionally(e);
return future;
} finally {
if (conn != null) writePool.offerConnection(conn);
}
}
@Override
protected CompletableFuture