This commit is contained in:
47
src/META-INF/persistence-template.xml
Normal file
47
src/META-INF/persistence-template.xml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
|
||||||
|
<persistence>
|
||||||
|
<!-- 系统基本库 -->
|
||||||
|
<persistence-unit name="demouser">
|
||||||
|
<!-- 为NONE表示不启动缓存,@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
|
||||||
|
<shared-cache-mode>NONE</shared-cache-mode>
|
||||||
|
<properties>
|
||||||
|
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
|
||||||
|
<!--
|
||||||
|
javax.persistence.jdbc.driver在JPA的值是JDBC驱动,Redkale有所不同,值应该是javax.sql.DataSource的子类。
|
||||||
|
为了兼容用户习惯,Redkale内置常见JDBC驱动到javax.sql.DataSource的映射关系:
|
||||||
|
com.mysql.jdbc.Driver —————— com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
|
||||||
|
org.mariadb.jdbc.Driver —————— org.mariadb.jdbc.MySQLDataSource
|
||||||
|
oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource
|
||||||
|
com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
|
||||||
|
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
|
||||||
|
-->
|
||||||
|
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
||||||
|
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||||
|
<property name="javax.persistence.jdbc.password" value="123456"/>
|
||||||
|
|
||||||
|
<!-- 最大连接数,默认值:CPU数*16 -->
|
||||||
|
<property name="javax.persistence.connections.limit" value="32"/>
|
||||||
|
|
||||||
|
<!-- 包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL、Oracle、Sqlserver的语句 -->
|
||||||
|
<property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
|
||||||
|
<property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
|
||||||
|
|
||||||
|
<!-- 复制表结构的SQL模板,Redkale内置了MySQL的语句 -->
|
||||||
|
<property name="javax.persistence.tablenotexist.sqlstate" value="42S02"/>
|
||||||
|
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
|
||||||
|
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
<!-- IM消息库 -->
|
||||||
|
<persistence-unit name="demoim">
|
||||||
|
<shared-cache-mode>NONE</shared-cache-mode>
|
||||||
|
<properties>
|
||||||
|
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&autoReconnectForPools=true&characterEncoding=utf8 -->
|
||||||
|
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
|
||||||
|
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
||||||
|
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||||
|
<property name="javax.persistence.jdbc.password" value="123456"/>
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
</persistence>
|
||||||
@@ -36,6 +36,10 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
|||||||
|
|
||||||
static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate";
|
static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate";
|
||||||
|
|
||||||
|
static final String JDBC_TABLENOTEXIST_SQLSTATE = "javax.persistence.tablenotexist.sqlstate";
|
||||||
|
|
||||||
|
static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate";
|
||||||
|
|
||||||
static final String JDBC_URL = "javax.persistence.jdbc.url";
|
static final String JDBC_URL = "javax.persistence.jdbc.url";
|
||||||
|
|
||||||
static final String JDBC_USER = "javax.persistence.jdbc.user";
|
static final String JDBC_USER = "javax.persistence.jdbc.user";
|
||||||
@@ -329,7 +333,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
|||||||
if (values.length == 0) return;
|
if (values.length == 0) return;
|
||||||
try {
|
try {
|
||||||
if (!info.isVirtualEntity()) {
|
if (!info.isVirtualEntity()) {
|
||||||
final String sql = info.insertSQL;
|
final String sql = info.getInsertSQL(values[0]);
|
||||||
final PreparedStatement prestmt = info.autoGenerated
|
final PreparedStatement prestmt = info.autoGenerated
|
||||||
? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
|
? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
|
||||||
final Class primaryType = info.getPrimary().type();
|
final Class primaryType = info.getPrimary().type();
|
||||||
@@ -340,7 +344,9 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
|||||||
if (distributed && !info.initedPrimaryValue && primaryType.isPrimitive()) { //由DataSource生成主键
|
if (distributed && !info.initedPrimaryValue && primaryType.isPrimitive()) { //由DataSource生成主键
|
||||||
synchronized (info) {
|
synchronized (info) {
|
||||||
if (!info.initedPrimaryValue) { //初始化最大主键值
|
if (!info.initedPrimaryValue) { //初始化最大主键值
|
||||||
|
try {
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
|
|
||||||
ResultSet rs = stmt.executeQuery("SELECT MAX(" + info.getPrimarySQLColumn() + ") FROM " + info.getTable(values[0]));
|
ResultSet rs = stmt.executeQuery("SELECT MAX(" + info.getPrimarySQLColumn() + ") FROM " + info.getTable(values[0]));
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
if (primaryType == int.class) {
|
if (primaryType == int.class) {
|
||||||
@@ -353,6 +359,9 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
|||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
stmt.close();
|
stmt.close();
|
||||||
|
} catch (SQLException se) {
|
||||||
|
if (info.tableStrategy == null) throw se;
|
||||||
|
}
|
||||||
info.initedPrimaryValue = true;
|
info.initedPrimaryValue = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +402,22 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
|||||||
sqls[index++] = sb.toString();
|
sqls[index++] = sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
prestmt.executeBatch();
|
prestmt.executeBatch();
|
||||||
|
} catch (SQLException se) {
|
||||||
|
if (info.tableStrategy == null || !info.tablenotexistSqlstate.equals(se.getSQLState())) throw se;
|
||||||
|
synchronized (info.tables) {
|
||||||
|
final String oldTable = info.table;
|
||||||
|
final String newTable = info.getTable(values[0]);
|
||||||
|
if (!info.tables.contains(newTable)) {
|
||||||
|
Statement st = conn.createStatement();
|
||||||
|
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
|
||||||
|
st.close();
|
||||||
|
info.tables.add(newTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prestmt.executeBatch();
|
||||||
|
}
|
||||||
if (writeListener != null) writeListener.insert(sqls);
|
if (writeListener != null) writeListener.insert(sqls);
|
||||||
if (info.autoGenerated) { //由数据库自动生成主键值
|
if (info.autoGenerated) { //由数据库自动生成主键值
|
||||||
ResultSet set = prestmt.getGeneratedKeys();
|
ResultSet set = prestmt.getGeneratedKeys();
|
||||||
|
|||||||
24
src/org/redkale/source/DistributeTable.java
Normal file
24
src/org/redkale/source/DistributeTable.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.lang.annotation.*;
|
||||||
|
import static java.lang.annotation.ElementType.*;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: http://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@Target({TYPE})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface DistributeTable {
|
||||||
|
|
||||||
|
Class<? extends DistributeTableStrategy> strategy();
|
||||||
|
}
|
||||||
29
src/org/redkale/source/DistributeTableStrategy.java
Normal file
29
src/org/redkale/source/DistributeTableStrategy.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: http://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public interface DistributeTableStrategy<T> {
|
||||||
|
|
||||||
|
default String getTable(String table, Serializable primary) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
default String getTable(String table, FilterNode node) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTable(String table, T bean);
|
||||||
|
}
|
||||||
@@ -37,7 +37,7 @@ public final class EntityInfo<T> {
|
|||||||
private final Class<T> type;
|
private final Class<T> type;
|
||||||
|
|
||||||
//类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null
|
//类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null
|
||||||
private final String table;
|
final String table;
|
||||||
|
|
||||||
private final Creator<T> creator;
|
private final Creator<T> creator;
|
||||||
|
|
||||||
@@ -62,11 +62,19 @@ public final class EntityInfo<T> {
|
|||||||
|
|
||||||
final String notcontainSQL; //用于反向LIKE使用
|
final String notcontainSQL; //用于反向LIKE使用
|
||||||
|
|
||||||
|
final String tablenotexistSqlstate; //用于判断表不存在的使用
|
||||||
|
|
||||||
|
final String tablecopySQL; //用于复制表结构使用
|
||||||
|
|
||||||
|
final Set<String> tables = new HashSet<>(); //用于存在table_20160202类似这种分布式表
|
||||||
|
|
||||||
|
final DistributeTableStrategy<T> tableStrategy;
|
||||||
|
|
||||||
final String querySQL;
|
final String querySQL;
|
||||||
|
|
||||||
private final Attribute<T, Serializable>[] queryAttributes; //数据库中所有字段
|
private final Attribute<T, Serializable>[] queryAttributes; //数据库中所有字段
|
||||||
|
|
||||||
final String insertSQL;
|
private String insertSQL;
|
||||||
|
|
||||||
final Attribute<T, Serializable>[] insertAttributes; //数据库中所有可新增字段
|
final Attribute<T, Serializable>[] insertAttributes; //数据库中所有可新增字段
|
||||||
|
|
||||||
@@ -145,6 +153,15 @@ public final class EntityInfo<T> {
|
|||||||
this.fullloader = fullloader;
|
this.fullloader = fullloader;
|
||||||
this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? t.name() : (t.catalog() + '.' + t.name());
|
this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? t.name() : (t.catalog() + '.' + t.name());
|
||||||
}
|
}
|
||||||
|
DistributeTable dt = type.getAnnotation(DistributeTable.class);
|
||||||
|
DistributeTableStrategy dts = null;
|
||||||
|
try {
|
||||||
|
dts = (dt == null) ? null : dt.strategy().newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.severe(type + " init DistributeTableStrategy error", e);
|
||||||
|
}
|
||||||
|
this.tableStrategy = dts;
|
||||||
|
|
||||||
this.creator = Creator.create(type);
|
this.creator = Creator.create(type);
|
||||||
Attribute idAttr0 = null;
|
Attribute idAttr0 = null;
|
||||||
Map<String, String> aliasmap0 = null;
|
Map<String, String> aliasmap0 = null;
|
||||||
@@ -231,7 +248,7 @@ public final class EntityInfo<T> {
|
|||||||
if (insertsb2.length() > 0) insertsb2.append(',');
|
if (insertsb2.length() > 0) insertsb2.append(',');
|
||||||
insertsb2.append('?');
|
insertsb2.append('?');
|
||||||
}
|
}
|
||||||
this.insertSQL = "INSERT INTO " + table + "(" + insertsb + ") VALUES(" + insertsb2 + ")";
|
this.insertSQL = "INSERT INTO " + (this.tableStrategy == null ? table : "${newtable}") + "(" + insertsb + ") VALUES(" + insertsb2 + ")";
|
||||||
StringBuilder updatesb = new StringBuilder();
|
StringBuilder updatesb = new StringBuilder();
|
||||||
for (String col : updatecols) {
|
for (String col : updatecols) {
|
||||||
if (updatesb.length() > 0) updatesb.append(", ");
|
if (updatesb.length() > 0) updatesb.append(", ");
|
||||||
@@ -259,6 +276,9 @@ public final class EntityInfo<T> {
|
|||||||
if (conf == null) conf = new Properties();
|
if (conf == null) conf = new Properties();
|
||||||
this.containSQL = conf.getProperty(JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0");
|
this.containSQL = conf.getProperty(JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0");
|
||||||
this.notcontainSQL = conf.getProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0");
|
this.notcontainSQL = conf.getProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0");
|
||||||
|
|
||||||
|
this.tablenotexistSqlstate = conf.getProperty(JDBC_TABLENOTEXIST_SQLSTATE, "42S02");
|
||||||
|
this.tablecopySQL = conf.getProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} LIKE ${oldtable}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createPrimaryValue(T src) {
|
public void createPrimaryValue(T src) {
|
||||||
@@ -295,16 +315,27 @@ public final class EntityInfo<T> {
|
|||||||
return table == null;
|
return table == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getInsertSQL(T bean) {
|
||||||
|
if (this.tableStrategy == null) return insertSQL;
|
||||||
|
return insertSQL.replace("${newtable}", getTable(bean));
|
||||||
|
}
|
||||||
|
|
||||||
public String getTable(Serializable primary) {
|
public String getTable(Serializable primary) {
|
||||||
return table;
|
if (tableStrategy == null) return table;
|
||||||
|
String t = tableStrategy.getTable(table, primary);
|
||||||
|
return t == null || t.isEmpty() ? table : t;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTable(FilterNode node) {
|
public String getTable(FilterNode node) {
|
||||||
return table;
|
if (tableStrategy == null) return table;
|
||||||
|
String t = tableStrategy.getTable(table, node);
|
||||||
|
return t == null || t.isEmpty() ? table : t;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTable(T bean) {
|
public String getTable(T bean) {
|
||||||
return table;
|
if (tableStrategy == null) return table;
|
||||||
|
String t = tableStrategy.getTable(table, bean);
|
||||||
|
return t == null || t.isEmpty() ? table : t;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attribute<T, Serializable> getPrimary() {
|
public Attribute<T, Serializable> getPrimary() {
|
||||||
|
|||||||
Reference in New Issue
Block a user