From 5b8f797b3398115afa4729c39109fd0742a56630 Mon Sep 17 00:00:00 2001 From: redkale Date: Wed, 26 Jul 2023 15:57:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=81=A2=E5=A4=8DGeneratedValue=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redkale/persistence/GeneratedValue.java | 62 +++++++++++++ .../redkale/source/AbstractDataSqlSource.java | 10 +- .../org/redkale/source/DataJdbcSource.java | 92 ++++++++++++++++++- .../org/redkale/source/DataSqlSource.java | 7 ++ .../java/org/redkale/source/EntityInfo.java | 16 +++- 5 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/redkale/persistence/GeneratedValue.java diff --git a/src/main/java/org/redkale/persistence/GeneratedValue.java b/src/main/java/org/redkale/persistence/GeneratedValue.java new file mode 100644 index 000000000..bd6e42300 --- /dev/null +++ b/src/main/java/org/redkale/persistence/GeneratedValue.java @@ -0,0 +1,62 @@ +/** ***************************************************************************** + * Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Linda DeMichiel - Java Persistence 2.1 + * Linda DeMichiel - Java Persistence 2.0 + * + ***************************************************************************** */ +package org.redkale.persistence; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.*; + +/** + * Provides for the specification of generation strategies for the + * values of primary keys. + * + *

+ * The GeneratedValue annotation + * may be applied to a primary key property or field of an entity or + * mapped superclass in conjunction with the {@link Id} annotation. + * The use of the GeneratedValue annotation is only + * required to be supported for simple primary keys. Use of the + * GeneratedValue annotation is not supported for derived + * primary keys. + * + *

+ *
+ *     Example 1:
+ *
+ *     @Id
+ *     @GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
+ *     @Column(name="CUST_ID")
+ *     public Long getId() { return id; }
+ *
+ *     Example 2:
+ *
+ *     @Id
+ *     @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
+ *     @Column(name="CUST_ID")
+ *     Long id;
+ * 
+ * + * @see Id + * + * @since Java Persistence 1.0 + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) + +public @interface GeneratedValue { + +} diff --git a/src/main/java/org/redkale/source/AbstractDataSqlSource.java b/src/main/java/org/redkale/source/AbstractDataSqlSource.java index 5bc454573..e160066b8 100644 --- a/src/main/java/org/redkale/source/AbstractDataSqlSource.java +++ b/src/main/java/org/redkale/source/AbstractDataSqlSource.java @@ -442,7 +442,9 @@ public abstract class AbstractDataSqlSource extends AbstractDataSource implement sqltype = column.length >= 65535 ? "TEXT" : ("VARCHAR(" + column.length + ")"); sqlnull = !column.nullable ? "NOT NULL DEFAULT ''" : "NULL"; } - sb.append(" `").append(column.column).append("` ").append(sqltype).append(" ").append(sqlnull); + sb.append(" `").append(column.column).append("` ").append(sqltype) + .append(column.primary && info.isAutoGenerated() ? " AUTO_INCREMENT " : " ") + .append(column.primary && info.isAutoGenerated() ? "" : sqlnull); if (column.comment != null && !column.comment.isEmpty()) { sb.append(" COMMENT '").append(column.comment.replace('\'', '"')).append("'"); } @@ -552,7 +554,11 @@ public abstract class AbstractDataSqlSource extends AbstractDataSource implement sqltype = column.length >= 65535 ? "TEXT" : ("VARCHAR(" + column.length + ")"); sqlnull = !column.nullable ? "NOT NULL DEFAULT ''" : "NULL"; } - sb.append(" ").append(column.column).append(" ").append(sqltype).append(" ").append(sqlnull); + if (column.primary && info.isAutoGenerated()) { + sqltype = "SERIAL"; + } + sb.append(" ").append(column.column).append(" ").append(sqltype).append(" ") + .append(column.primary && info.isAutoGenerated() ? "" : sqlnull); if (column.comment != null && !column.comment.isEmpty()) { //postgresql不支持DDL中直接带comment comments.add("COMMENT ON COLUMN " + info.getOriginTable() + "." + column.column + " IS '" + column.comment.replace('\'', '"') + "'"); diff --git a/src/main/java/org/redkale/source/DataJdbcSource.java b/src/main/java/org/redkale/source/DataJdbcSource.java index 14416f15d..525ee4181 100644 --- a/src/main/java/org/redkale/source/DataJdbcSource.java +++ b/src/main/java/org/redkale/source/DataJdbcSource.java @@ -135,7 +135,9 @@ public class DataJdbcSource extends AbstractDataSqlSource { final List prestmts = new ArrayList<>(); for (Map.Entry> en : prepareInfos.entrySet()) { PrepareInfo prepareInfo = en.getValue(); - PreparedStatement prestmt = conn.prepareUpdateStatement(prepareInfo.prepareSql); + PreparedStatement prestmt = info.isAutoGenerated() + ? conn.prepareUpdateStatement(prepareInfo.prepareSql, Statement.RETURN_GENERATED_KEYS) + : conn.prepareUpdateStatement(prepareInfo.prepareSql); for (final T value : prepareInfo.entitys) { bindStatementParameters(conn, prestmt, info, attrs, value); prestmt.addBatch(); @@ -147,7 +149,9 @@ public class DataJdbcSource extends AbstractDataSqlSource { protected PreparedStatement prepareInsertEntityStatement(SourceConnection conn, String sql, EntityInfo info, T... entitys) throws SQLException { Attribute[] attrs = info.insertAttributes; - final PreparedStatement prestmt = conn.prepareUpdateStatement(sql); + final PreparedStatement prestmt = info.isAutoGenerated() + ? conn.prepareUpdateStatement(sql, Statement.RETURN_GENERATED_KEYS) + : conn.prepareUpdateStatement(sql); for (final T value : entitys) { bindStatementParameters(conn, prestmt, info, attrs, value); prestmt.addBatch(); @@ -341,6 +345,8 @@ public class DataJdbcSource extends AbstractDataSqlSource { PreparedStatement prestmt = null; List prestmts = null; Map> prepareInfos = null; + final Attribute primary = info.getPrimary(); + final Class primaryType = primary.type(); Attribute[] attrs = info.insertAttributes; if (info.getTableStrategy() == null) { //单库单表 presql = info.getInsertQuestionPrepareSQL(entitys[0]); @@ -352,6 +358,23 @@ public class DataJdbcSource extends AbstractDataSqlSource { try { if (info.getTableStrategy() == null) { //单库单表 c = Utility.sum(prestmt.executeBatch()); + if (info.isAutoGenerated()) { //由数据库自动生成主键值 + ResultSet set = prestmt.getGeneratedKeys(); + int i = -1; + while (set.next()) { + T entity = entitys[++i]; + if (primaryType == int.class || primaryType == Integer.class) { + primary.set(entity, set.getInt(1)); + } else if (primaryType == long.class || primaryType == long.class) { + primary.set(entity, set.getLong(1)); + } else if (primaryType == String.class) { + primary.set(entity, set.getString(1)); + } else { + primary.set(entity, set.getObject(1)); + } + } + set.close(); + } conn.offerUpdateStatement(prestmt); } else { //分库分表 int c1 = 0; @@ -359,6 +382,28 @@ public class DataJdbcSource extends AbstractDataSqlSource { c1 += Utility.sum(stmt.executeBatch()); } c = c1; + if (info.isAutoGenerated()) { //由数据库自动生成主键值 + int j = -1; + for (Map.Entry> en : prepareInfos.entrySet()) { + PrepareInfo prepareInfo = en.getValue(); + PreparedStatement stmt = prestmts.get(++j); + ResultSet set = stmt.getGeneratedKeys(); + int i = -1; + while (set.next()) { + T entity = prepareInfo.entitys.get(++i); + if (primaryType == int.class || primaryType == Integer.class) { + primary.set(entity, set.getInt(1)); + } else if (primaryType == long.class || primaryType == long.class) { + primary.set(entity, set.getLong(1)); + } else if (primaryType == String.class) { + primary.set(entity, set.getString(1)); + } else { + primary.set(entity, set.getObject(1)); + } + } + set.close(); + } + } for (PreparedStatement stmt : prestmts) { conn.offerUpdateStatement(stmt); } @@ -490,6 +535,23 @@ public class DataJdbcSource extends AbstractDataSqlSource { conn.offerUpdateStatement(prestmt); prestmt = prepareInsertEntityStatement(conn, presql, info, entitys); c = Utility.sum(prestmt.executeBatch()); + if (info.isAutoGenerated()) { //由数据库自动生成主键值 + ResultSet set = prestmt.getGeneratedKeys(); + int i = -1; + while (set.next()) { + T entity = entitys[++i]; + if (primaryType == int.class || primaryType == Integer.class) { + primary.set(entity, set.getInt(1)); + } else if (primaryType == long.class || primaryType == long.class) { + primary.set(entity, set.getLong(1)); + } else if (primaryType == String.class) { + primary.set(entity, set.getString(1)); + } else { + primary.set(entity, set.getObject(1)); + } + } + set.close(); + } conn.offerUpdateStatement(prestmt); } else { //分库分表 for (PreparedStatement stmt : prestmts) { @@ -501,6 +563,28 @@ public class DataJdbcSource extends AbstractDataSqlSource { c1 += Utility.sum(stmt.executeBatch()); } c = c1; + if (info.isAutoGenerated()) { //由数据库自动生成主键值 + int j = -1; + for (Map.Entry> en : prepareInfos.entrySet()) { + PrepareInfo prepareInfo = en.getValue(); + PreparedStatement stmt = prestmts.get(++j); + ResultSet set = stmt.getGeneratedKeys(); + int i = -1; + while (set.next()) { + T entity = prepareInfo.entitys.get(++i); + if (primaryType == int.class || primaryType == Integer.class) { + primary.set(entity, set.getInt(1)); + } else if (primaryType == long.class || primaryType == long.class) { + primary.set(entity, set.getLong(1)); + } else if (primaryType == String.class) { + primary.set(entity, set.getString(1)); + } else { + primary.set(entity, set.getObject(1)); + } + } + set.close(); + } + } for (PreparedStatement stmt : prestmts) { conn.offerUpdateStatement(stmt); } @@ -2897,6 +2981,10 @@ public class DataJdbcSource extends AbstractDataSqlSource { return conn.prepareStatement(sql); } + public PreparedStatement prepareUpdateStatement(String sql, int resultSetType) throws SQLException { + return conn.prepareStatement(sql, resultSetType); + } + public void offerUpdateStatement(final PreparedStatement stmt) throws SQLException { stmt.close(); } diff --git a/src/main/java/org/redkale/source/DataSqlSource.java b/src/main/java/org/redkale/source/DataSqlSource.java index 842f087c6..643ecf673 100644 --- a/src/main/java/org/redkale/source/DataSqlSource.java +++ b/src/main/java/org/redkale/source/DataSqlSource.java @@ -67,4 +67,11 @@ public interface DataSqlSource extends DataSource { }); } + default Map executeQueryStrStrMap(String sql) { + return executeQueryMap(String.class, String.class, sql); + } + + default Map executeQueryIntStrMap(String sql) { + return executeQueryMap(Integer.class, String.class, sql); + } } diff --git a/src/main/java/org/redkale/source/EntityInfo.java b/src/main/java/org/redkale/source/EntityInfo.java index 2eca9c1c5..6696aa823 100644 --- a/src/main/java/org/redkale/source/EntityInfo.java +++ b/src/main/java/org/redkale/source/EntityInfo.java @@ -72,6 +72,9 @@ public final class EntityInfo { //DDL字段 final EntityColumn[] primaryColumnOneArray; + //是否由数据库生成主键值 + private final boolean autoGenerated; + //DDL字段集合 final EntityColumn[] ddlColumns; @@ -381,6 +384,7 @@ public final class EntityInfo { } catch (Exception e) { logger.log(Level.SEVERE, type + " cannot find ConstructorParameters Creator", e); } + boolean auto = false; String[] constructorParameters = cps; Attribute idAttr0 = null; Map aliasmap = null; @@ -431,9 +435,12 @@ public final class EntityInfo { boolean idFlag = field.getAnnotation(Id.class) != null || field.getAnnotation(javax.persistence.Id.class) != null; if (idFlag && idAttr0 == null) { + auto = field.getAnnotation(GeneratedValue.class) != null; idAttr0 = attr; - insertCols.add(sqlField); - insertAttrs.add(attr); + if (!auto) { + insertCols.add(sqlField); + insertAttrs.add(attr); + } RedkaleClassLoader.putReflectionField(cltmp.getName(), field); } else { if (col == null || col.insertable()) { @@ -488,6 +495,7 @@ public final class EntityInfo { } while ((cltmp = cltmp.getSuperclass()) != Object.class); this.jsonConvert = convert == null ? DEFAULT_JSON_CONVERT : convert; + this.autoGenerated = auto; this.primary = idAttr0; this.primaryOneArray = new Attribute[]{this.primary}; List ddls = new ArrayList<>(); @@ -777,6 +785,10 @@ public final class EntityInfo { return table == null; } + public boolean isAutoGenerated() { + return autoGenerated; + } + public DistributeTableStrategy getTableStrategy() { return tableStrategy; }