mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
108
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3127bc2154 | ||
|
|
8aa1ed6676 | ||
|
|
8a0dea1218 | ||
|
|
1e266a1532 | ||
|
|
57cfd25eb5 | ||
|
|
2bcce2e648 | ||
|
|
f6e45a6999 | ||
|
|
fa3de7158e | ||
|
|
792785dabe | ||
|
|
d0cd74b400 | ||
|
|
71d762ab97 | ||
|
|
e00713aa29 | ||
|
|
d70a49e105 | ||
|
|
159a9a8e54 | ||
|
|
db027eb030 | ||
|
|
ec55b2f096 | ||
|
|
b854943a86 | ||
|
|
8a263d243c | ||
|
|
0a4f93adc5 | ||
|
|
ffb11019fa | ||
|
|
6fcac27dfe | ||
|
|
71295077a5 | ||
|
|
ddbad284ad | ||
|
|
1fcec429b0 | ||
|
|
c6062fe93e | ||
|
|
d8d35b7dd9 | ||
|
|
590cd07d67 | ||
|
|
5cd74bc468 | ||
|
|
502b20be67 | ||
|
|
b3077d44f6 | ||
|
|
d4b35cb445 | ||
|
|
91e7540a39 | ||
|
|
06bd60aaf7 | ||
|
|
3db2a69312 | ||
|
|
5a983b9e0d | ||
|
|
ab7b34779a | ||
|
|
c7aad6078e | ||
|
|
ccfe9c39cd | ||
|
|
dbdac04883 | ||
|
|
1d369c002d | ||
|
|
5a1be81603 | ||
|
|
dee73da1aa | ||
|
|
a7dde87c5f | ||
|
|
60fadd448d | ||
|
|
0140d09007 | ||
|
|
da5604a38d | ||
|
|
937df1395c | ||
|
|
89c05007c2 | ||
|
|
4cc9278183 | ||
|
|
9841a2c03a | ||
|
|
74929472d9 | ||
|
|
e274a4c512 | ||
|
|
5d93c44475 | ||
|
|
63b802d0b8 | ||
|
|
1d7e751b60 | ||
|
|
5f8690fb87 | ||
|
|
e093675444 | ||
|
|
a04594540c | ||
|
|
269f2de333 | ||
|
|
be12910aec | ||
|
|
996e582a85 | ||
|
|
aa4c6b7889 | ||
|
|
27a4e8951d | ||
|
|
1fc4082abe | ||
|
|
1c5d7a97e1 | ||
|
|
67c2e1d24c | ||
|
|
eb292e017e | ||
|
|
88839f7613 | ||
|
|
ca71fef74a | ||
|
|
6c91ed0c76 | ||
|
|
8761c0486d | ||
|
|
fee6a9f04a | ||
|
|
17ff04e2b9 | ||
|
|
aa11095d17 | ||
|
|
c2a30f786f | ||
|
|
9b0dd2b0c4 | ||
|
|
aa96d10491 | ||
|
|
dfefbecf44 | ||
|
|
738f19491a | ||
|
|
61257bea7f | ||
|
|
566a01d815 | ||
|
|
a7116d1606 | ||
|
|
615a2aea46 | ||
|
|
20d538c428 | ||
|
|
01054bf470 | ||
|
|
affd720390 | ||
|
|
7d77df58c5 | ||
|
|
51fad2dec6 | ||
|
|
997378ce72 | ||
|
|
1a8a43603e | ||
|
|
d2c88bf7c6 | ||
|
|
0929147b08 | ||
|
|
ecab219635 | ||
|
|
7a974320ed | ||
|
|
1b7dc83a9a | ||
|
|
9827d9056f | ||
|
|
c8d5d9b552 | ||
|
|
dac55ab8e9 | ||
|
|
de75bcdaf9 | ||
|
|
5785124a2b | ||
|
|
4d1c0bfaa8 | ||
|
|
9a29c988cd | ||
|
|
80309f844e | ||
|
|
56ddc49ab4 | ||
|
|
1e7de83019 | ||
|
|
1db1f0312a | ||
|
|
d27bf14887 | ||
|
|
d4e7d4eebc |
@@ -44,4 +44,3 @@ Goto [https://ebean.io/docs/](https://ebean.io/docs/)
|
||||
## Other versions
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>java8-parent</artifactId>
|
||||
<version>1.4</version>
|
||||
<artifactId>java8-oss</artifactId>
|
||||
<version>2.1</version>
|
||||
</parent>
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>12.1.1</version>
|
||||
<version>12.1.9</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-12.1.1</tag>
|
||||
<tag>ebean-12.1.9</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -124,25 +124,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-types</artifactId>
|
||||
<version>1.3</version>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>4.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>4.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>12.1.1</version>
|
||||
<version>12.1.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -199,7 +193,7 @@
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>2.4.0-b180830.0438</version>
|
||||
<version>2.3.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -314,9 +308,9 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.moduuid</groupId>
|
||||
<artifactId>avaje-moduuid</artifactId>
|
||||
<version>2.1</version>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>mod-uuid</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -329,13 +323,13 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.1.1</version>
|
||||
<version>12.1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
<transformArgs>debug=0</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>testEnhance</goal>
|
||||
@@ -390,23 +384,7 @@
|
||||
<configuration>
|
||||
<doctitle>Ebean 12</doctitle>
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>io.ebeaninternal.*:io.ebeanservice:io.ebean.common:io.ebean.bean:io.ebean.service:io.ebean.metric:io.ebean.util:io.ebean.config.properties:io.ebean.config.dbplatform</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</docletArtifact>
|
||||
<!-- for people using JDK11, our javadoc doclet isn't 11 compatible yet -->
|
||||
<!-- <javadocExecutable>${env.JAVA8_HOME}/bin/javadoc</javadocExecutable>-->
|
||||
<additionalparam>
|
||||
-Xdoclint:none
|
||||
-include-basedir ${project.basedir}
|
||||
-attributes "idseparator=-; project_name=${project.name}; \
|
||||
project_version=${project.version}; \
|
||||
project_desc=${project.description}"
|
||||
</additionalparam>
|
||||
<linksource>true</linksource>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
</configuration>
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.plugin.Property;
|
||||
import io.ebean.text.csv.CsvReader;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
@@ -737,8 +736,11 @@ public class DB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to sqlQuery().
|
||||
* <p>
|
||||
* This is an alias for {@link #sqlQuery(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static SqlQuery createSqlQuery(String sql) {
|
||||
return sqlQuery(sql);
|
||||
}
|
||||
@@ -761,8 +763,11 @@ public class DB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to sqlUpdate().
|
||||
* <p>
|
||||
* This is an alias for {@link #sqlUpdate(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static SqlUpdate createSqlUpdate(String sql) {
|
||||
return sqlUpdate(sql);
|
||||
}
|
||||
@@ -1203,6 +1208,13 @@ public class DB {
|
||||
return getDefault().getBeanState(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the Id property for a given bean.
|
||||
*/
|
||||
public static Object getBeanId(Object bean) {
|
||||
return getDefault().getBeanId(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the manager of the level 2 cache ("L2" cache).
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.ebean;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.plugin.Property;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
@@ -465,8 +464,11 @@ public interface Database {
|
||||
SqlQuery sqlQuery(String sql);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to sqlQuery().
|
||||
* <p>
|
||||
* This is an alias for {@link #sqlQuery(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
SqlQuery createSqlQuery(String sql);
|
||||
|
||||
/**
|
||||
@@ -485,8 +487,11 @@ public interface Database {
|
||||
SqlUpdate sqlUpdate(String sql);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to sqlUpdate().
|
||||
* <p>
|
||||
* This is an alias for {@link #sqlUpdate(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
SqlUpdate createSqlUpdate(String sql);
|
||||
|
||||
/**
|
||||
@@ -856,7 +861,7 @@ public interface Database {
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
@@ -1051,7 +1056,6 @@ public interface Database {
|
||||
* Integer returnValue = (Integer) cs.getObject(3);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
int execute(CallableSql callableSql);
|
||||
|
||||
@@ -1299,7 +1303,7 @@ public interface Database {
|
||||
* public void run() {
|
||||
* User u1 = database.find(User.class, 1);
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
@@ -1348,7 +1352,7 @@ public interface Database {
|
||||
* User u1 = database.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
|
||||
@@ -24,6 +24,8 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Ebean will be Deprecated - please migrate to use DB.
|
||||
* <p>
|
||||
* Ebean is a registry of {@link Database} by name. Ebean has now been renamed to {@link DB}.
|
||||
* <p>
|
||||
* Ebean is effectively this is an alias for {@link DB} which is the new and improved name for Ebean.
|
||||
@@ -462,7 +464,7 @@ public final class Ebean {
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
@@ -865,6 +867,8 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to DB.sqlQuery().
|
||||
* <p>
|
||||
* Create a SqlQuery for executing native sql
|
||||
* query statements.
|
||||
* <p>
|
||||
@@ -872,22 +876,24 @@ public final class Ebean {
|
||||
* annotation for examples.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
public static SqlQuery createSqlQuery(String sql) {
|
||||
return serverMgr.getDefaultServer().createSqlQuery(sql);
|
||||
return serverMgr.getDefaultServer().sqlQuery(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to DB.sqlUpdate().
|
||||
* <p>
|
||||
* Create a sql update for executing native dml statements.
|
||||
* <p>
|
||||
* Use this to execute a Insert Update or Delete statement. The statement will
|
||||
* be native to the database and contain database table and column names.
|
||||
* </p>
|
||||
* <p>
|
||||
* See {@link SqlUpdate} for example usage.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
public static SqlUpdate createSqlUpdate(String sql) {
|
||||
return serverMgr.getDefaultServer().createSqlUpdate(sql);
|
||||
return serverMgr.getDefaultServer().sqlUpdate(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1193,7 +1199,7 @@ public final class Ebean {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
@@ -1245,7 +1251,7 @@ public final class Ebean {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
|
||||
@@ -21,7 +21,7 @@ public class EbeanVersion {
|
||||
static {
|
||||
try {
|
||||
Properties prop = new Properties();
|
||||
try (InputStream in = Ebean.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
|
||||
try (InputStream in = DB.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
|
||||
if (in != null) {
|
||||
prop.load(in);
|
||||
in.close();
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* An empty PagedList.
|
||||
* <p>
|
||||
* For use in application code when we need to return a PagedList but don't want to
|
||||
* execute a query.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Customer> empty = PagedList.emptyList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class EmptyPagedList<T> implements PagedList<T> {
|
||||
|
||||
@Override
|
||||
public void loadCount() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Future<Integer> getFutureCount() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<T> getList() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalPageCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrev() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayXtoYofZ(String to, String of) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -34,14 +34,14 @@ public class Expr {
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
public static Expression eq(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().eq(propertyName, value);
|
||||
return DB.getExpressionFactory().eq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
public static Expression ne(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ne(propertyName, value);
|
||||
return DB.getExpressionFactory().ne(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +49,7 @@ public class Expr {
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
public static Expression ieq(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ieq(propertyName, value);
|
||||
return DB.getExpressionFactory().ieq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,28 +59,28 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression inRange(String propertyName, Object value1, Object value2) {
|
||||
return Ebean.getExpressionFactory().inRange(propertyName, value1, value2);
|
||||
return DB.getExpressionFactory().inRange(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public static Expression between(String propertyName, Object value1, Object value2) {
|
||||
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
|
||||
return DB.getExpressionFactory().between(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
public static Expression between(String lowProperty, String highProperty, Object value) {
|
||||
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
return DB.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
public static Expression gt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().gt(propertyName, value);
|
||||
return DB.getExpressionFactory().gt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,42 +88,42 @@ public class Expr {
|
||||
* value.
|
||||
*/
|
||||
public static Expression ge(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ge(propertyName, value);
|
||||
return DB.getExpressionFactory().ge(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
public static Expression lt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().lt(propertyName, value);
|
||||
return DB.getExpressionFactory().lt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
public static Expression le(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().le(propertyName, value);
|
||||
return DB.getExpressionFactory().le(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
public static Expression isNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNull(propertyName);
|
||||
return DB.getExpressionFactory().isNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
public static Expression isNotNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotNull(propertyName);
|
||||
return DB.getExpressionFactory().isNotNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
public static ExampleExpression iexampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().iexampleLike(example);
|
||||
return DB.getExpressionFactory().iexampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,14 +131,14 @@ public class Expr {
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example);
|
||||
return DB.getExpressionFactory().exampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
return DB.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +146,7 @@ public class Expr {
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
public static Expression like(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().like(propertyName, value);
|
||||
return DB.getExpressionFactory().like(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,14 +155,14 @@ public class Expr {
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression ilike(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ilike(propertyName, value);
|
||||
return DB.getExpressionFactory().ilike(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
public static Expression startsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().startsWith(propertyName, value);
|
||||
return DB.getExpressionFactory().startsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,14 +170,14 @@ public class Expr {
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression istartsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
|
||||
return DB.getExpressionFactory().istartsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
public static Expression endsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().endsWith(propertyName, value);
|
||||
return DB.getExpressionFactory().endsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,14 +185,14 @@ public class Expr {
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression iendsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
|
||||
return DB.getExpressionFactory().iendsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
public static Expression contains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().contains(propertyName, value);
|
||||
return DB.getExpressionFactory().contains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,42 +200,42 @@ public class Expr {
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression icontains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().icontains(propertyName, value);
|
||||
return DB.getExpressionFactory().icontains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are empty (have not existing elements).
|
||||
*/
|
||||
public static Expression isEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isEmpty(propertyName);
|
||||
return DB.getExpressionFactory().isEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are not empty (have existing elements).
|
||||
*/
|
||||
public static Expression isNotEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotEmpty(propertyName);
|
||||
return DB.getExpressionFactory().isNotEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Object[] values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
return DB.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
public static Expression in(String propertyName, Query<?> subQuery) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, subQuery);
|
||||
return DB.getExpressionFactory().in(propertyName, subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
return DB.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,14 +272,14 @@ public class Expr {
|
||||
* }</pre>
|
||||
*/
|
||||
public static Expression inOrEmpty(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().inOrEmpty(propertyName, values);
|
||||
return DB.getExpressionFactory().inOrEmpty(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
public static Expression idEq(Object value) {
|
||||
return Ebean.getExpressionFactory().idEq(value);
|
||||
return DB.getExpressionFactory().idEq(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,7 +292,7 @@ public class Expr {
|
||||
* @param propertyMap a map keyed by property names.
|
||||
*/
|
||||
public static Expression allEq(Map<String, Object> propertyMap) {
|
||||
return Ebean.getExpressionFactory().allEq(propertyMap);
|
||||
return DB.getExpressionFactory().allEq(propertyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,7 +303,7 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object value) {
|
||||
return Ebean.getExpressionFactory().raw(raw, value);
|
||||
return DB.getExpressionFactory().raw(raw, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,14 +314,14 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object[] values) {
|
||||
return Ebean.getExpressionFactory().raw(raw, values);
|
||||
return DB.getExpressionFactory().raw(raw, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
public static Expression raw(String raw) {
|
||||
return Ebean.getExpressionFactory().raw(raw);
|
||||
return DB.getExpressionFactory().raw(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,7 +329,7 @@ public class Expr {
|
||||
*/
|
||||
public static Expression and(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().and(expOne, expTwo);
|
||||
return DB.getExpressionFactory().and(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -337,7 +337,7 @@ public class Expr {
|
||||
*/
|
||||
public static Expression or(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().or(expOne, expTwo);
|
||||
return DB.getExpressionFactory().or(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +345,7 @@ public class Expr {
|
||||
*/
|
||||
public static Expression not(Expression exp) {
|
||||
|
||||
return Ebean.getExpressionFactory().not(exp);
|
||||
return DB.getExpressionFactory().not(exp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,7 +353,7 @@ public class Expr {
|
||||
*/
|
||||
public static <T> Junction<T> conjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().conjunction(query);
|
||||
return DB.getExpressionFactory().conjunction(query);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -361,6 +361,6 @@ public class Expr {
|
||||
*/
|
||||
public static <T> Junction<T> disjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().disjunction(query);
|
||||
return DB.getExpressionFactory().disjunction(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public interface Filter<T> {
|
||||
* expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* Refer to {@link Ebean#sort(List, String)} for more detail.
|
||||
* Refer to {@link DB#sort(List, String)} for more detail.
|
||||
* </p>
|
||||
*/
|
||||
Filter<T> sort(String sortByClause);
|
||||
|
||||
@@ -60,6 +60,13 @@ import java.util.concurrent.Future;
|
||||
*/
|
||||
public interface PagedList<T> {
|
||||
|
||||
/**
|
||||
* Return an empty PagedList.
|
||||
*/
|
||||
static <B> PagedList<B> emptyList() {
|
||||
return new EmptyPagedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the loading of the total row count in the background.
|
||||
* <pre>{@code
|
||||
|
||||
@@ -38,7 +38,7 @@ public interface ProfileLocation {
|
||||
/**
|
||||
* Return a short version of the location description.
|
||||
*/
|
||||
String shortDescription();
|
||||
String location();
|
||||
|
||||
/**
|
||||
* Return the short label.
|
||||
|
||||
@@ -126,8 +126,6 @@ public interface SqlUpdate {
|
||||
* {@link Transaction#setBatchMode(boolean)} and
|
||||
* {@link Transaction#setBatchSize(int)}.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
int execute();
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ public interface Transaction extends AutoCloseable {
|
||||
* @see Database#currentTransaction()
|
||||
*/
|
||||
static Transaction current() {
|
||||
return Ebean.currentTransaction();
|
||||
return DB.currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,16 +12,16 @@ import java.util.concurrent.Callable;
|
||||
* <p>
|
||||
* This information matches the features of the Transactional annotation. You
|
||||
* can use it directly with Runnable or Callable via
|
||||
* {@link Ebean#execute(TxScope, Runnable)} or
|
||||
* {@link Ebean#executeCall(TxScope, Callable)}.
|
||||
* {@link DB#execute(TxScope, Runnable)} or
|
||||
* {@link DB#executeCall(TxScope, Callable)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This object is used internally with the enhancement of a method with
|
||||
* Transactional annotation.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#execute(TxScope, Runnable)
|
||||
* @see Ebean#executeCall(TxScope, Callable)
|
||||
* @see DB#execute(TxScope, Runnable)
|
||||
* @see DB#executeCall(TxScope, Callable)
|
||||
*/
|
||||
public final class TxScope {
|
||||
|
||||
|
||||
@@ -20,29 +20,23 @@ class XServiceProvider {
|
||||
private static SpiFetchGroupService fetchGroupService = initSpiFetchGroupService();
|
||||
|
||||
private static SpiFetchGroupService initSpiFetchGroupService() {
|
||||
Iterator<SpiFetchGroupService> loader = ServiceLoader.load(SpiFetchGroupService.class).iterator();
|
||||
if (loader.hasNext()) {
|
||||
return loader.next();
|
||||
}
|
||||
throw new IllegalStateException("No service implementation found for SpiFetchGroupService?");
|
||||
return loadFirstService(SpiFetchGroupService.class);
|
||||
}
|
||||
|
||||
private static SpiRawSqlService initRawSql() {
|
||||
|
||||
Iterator<SpiRawSqlService> loader = ServiceLoader.load(SpiRawSqlService.class).iterator();
|
||||
if (loader.hasNext()) {
|
||||
return loader.next();
|
||||
}
|
||||
throw new IllegalStateException("No service implementation found for SpiRawSqlService?");
|
||||
return loadFirstService(SpiRawSqlService.class);
|
||||
}
|
||||
|
||||
private static SpiProfileLocationFactory initProfileLocation() {
|
||||
return loadFirstService(SpiProfileLocationFactory.class);
|
||||
}
|
||||
|
||||
Iterator<SpiProfileLocationFactory> loader = ServiceLoader.load(SpiProfileLocationFactory.class).iterator();
|
||||
private static <T> T loadFirstService(Class<T> cls) {
|
||||
Iterator<T> loader = ServiceLoader.load(cls).iterator();
|
||||
if (loader.hasNext()) {
|
||||
return loader.next();
|
||||
}
|
||||
throw new IllegalStateException("No service implementation found for SpiProfileLocationFactory?");
|
||||
throw new IllegalStateException("No service implementation found for " + cls);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.ValuePair;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
@@ -821,7 +821,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
synchronized (this) {
|
||||
if (beanLoader == null) {
|
||||
BeanLoader serverLoader = (BeanLoader) Ebean.getServer(ebeanServerName);
|
||||
BeanLoader serverLoader = (BeanLoader) DB.byName(ebeanServerName);
|
||||
if (serverLoader == null) {
|
||||
throw new PersistenceException("Server [" + ebeanServerName + "] was not found?");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.common;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
@@ -93,7 +93,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
void lazyLoadCollection(boolean onlyIds) {
|
||||
if (loader == null) {
|
||||
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
|
||||
loader = (BeanCollectionLoader) DB.byName(ebeanServerName);
|
||||
}
|
||||
loader.loadMany(this, onlyIds);
|
||||
checkEmptyLazyLoad();
|
||||
|
||||
@@ -88,7 +88,6 @@ public class DbConstraintNaming {
|
||||
* Return the primary key constraint name.
|
||||
*/
|
||||
public String primaryKeyName(String tableName) {
|
||||
|
||||
return pkPrefix + normaliseTable(tableName) + pkSuffix;
|
||||
}
|
||||
|
||||
@@ -103,7 +102,6 @@ public class DbConstraintNaming {
|
||||
* Return the index name associated with a foreign key constraint given multiple columns.
|
||||
*/
|
||||
public String foreignKeyIndexName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
|
||||
}
|
||||
@@ -112,7 +110,6 @@ public class DbConstraintNaming {
|
||||
* Return the index name associated with a foreign key constraint given a single column foreign key.
|
||||
*/
|
||||
public String foreignKeyIndexName(String tableName, String column) {
|
||||
|
||||
String colPart = normaliseTable(column);
|
||||
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
|
||||
}
|
||||
@@ -121,7 +118,6 @@ public class DbConstraintNaming {
|
||||
* Return the index name for a general index (not associated with a foreign key).
|
||||
*/
|
||||
public String indexName(String tableName, String column) {
|
||||
|
||||
String colPart = normaliseTable(column);
|
||||
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
|
||||
}
|
||||
@@ -130,7 +126,6 @@ public class DbConstraintNaming {
|
||||
* Return the index name for a general index (not associated with a foreign key).
|
||||
*/
|
||||
public String indexName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
|
||||
}
|
||||
@@ -139,7 +134,6 @@ public class DbConstraintNaming {
|
||||
* Join the column names together with underscores.
|
||||
*/
|
||||
protected String joinColumnNames(String[] columns) {
|
||||
|
||||
if (columns.length == 1) {
|
||||
return normaliseColumn(columns[0]);
|
||||
}
|
||||
@@ -157,7 +151,6 @@ public class DbConstraintNaming {
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
public String uniqueConstraintName(String tableName, String columnName) {
|
||||
|
||||
return uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix;
|
||||
}
|
||||
|
||||
@@ -165,7 +158,6 @@ public class DbConstraintNaming {
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
public String uniqueConstraintName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return uqPrefix + normaliseTable(tableName) + "_" + colPart + uqSuffix;
|
||||
}
|
||||
@@ -174,7 +166,6 @@ public class DbConstraintNaming {
|
||||
* Return the check constraint name.
|
||||
*/
|
||||
public String checkConstraintName(String tableName, String columnName) {
|
||||
|
||||
return ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used by generated code to hold entity classes to register with Ebean.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ModuleInfo {
|
||||
|
||||
/**
|
||||
* Returns the entity classes with db name prefix.
|
||||
* <p>
|
||||
* The db name prefix is added to entity classes for non default databases.
|
||||
*/
|
||||
String[] entities() default {};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Loads and returns entity classes to register with Ebean databases.
|
||||
*/
|
||||
public interface ModuleInfoLoader {
|
||||
|
||||
/**
|
||||
* Return the entity classes to register with the default DB.
|
||||
*/
|
||||
List<Class<?>> entityClasses();
|
||||
|
||||
/**
|
||||
* Return entity classes to register for a named DB (not default DB).
|
||||
*/
|
||||
List<Class<?>> entityClassesFor(String dbName);
|
||||
}
|
||||
@@ -17,6 +17,13 @@ public class PlatformConfig {
|
||||
|
||||
private boolean allQuotedIdentifiers;
|
||||
|
||||
private DbConstraintNaming constraintNaming;
|
||||
|
||||
/**
|
||||
* Flag set when a supplied constraintNaming is used.
|
||||
*/
|
||||
private boolean customConstraintNaming;
|
||||
|
||||
/**
|
||||
* The database boolean true value (typically either 1, T, or Y).
|
||||
*/
|
||||
@@ -63,7 +70,7 @@ public class PlatformConfig {
|
||||
* Construct with defaults.
|
||||
*/
|
||||
public PlatformConfig() {
|
||||
|
||||
this.constraintNaming = new DbConstraintNaming();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +87,19 @@ public class PlatformConfig {
|
||||
this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers;
|
||||
this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar;
|
||||
this.customDbTypeMappings = platformConfig.customDbTypeMappings;
|
||||
this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers);
|
||||
}
|
||||
|
||||
public DbConstraintNaming getConstraintNaming() {
|
||||
return constraintNaming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom database constraint naming convention.
|
||||
*/
|
||||
public void setConstraintNaming(DbConstraintNaming constraintNaming) {
|
||||
this.customConstraintNaming = true;
|
||||
this.constraintNaming = constraintNaming;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +114,9 @@ public class PlatformConfig {
|
||||
*/
|
||||
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
|
||||
this.allQuotedIdentifiers = allQuotedIdentifiers;
|
||||
if (!customConstraintNaming) {
|
||||
this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,6 @@ import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
|
||||
@@ -133,6 +132,15 @@ public class ServerConfig {
|
||||
|
||||
private TenantCatalogProvider tenantCatalogProvider;
|
||||
|
||||
/**
|
||||
* When true will load entity classes via ModuleInfoLoader.
|
||||
* <p>
|
||||
* NB: ModuleInfoLoader implementations are generated by querybean generator.
|
||||
* Having this on and registering entity classes means we don't need to manually
|
||||
* write that code or use classpath scanning to find entity classes.
|
||||
*/
|
||||
private boolean loadModuleInfo;
|
||||
|
||||
/**
|
||||
* List of interesting classes such as entities, embedded, ScalarTypes,
|
||||
* Listeners, Finders, Controllers etc.
|
||||
@@ -345,11 +353,6 @@ public class ServerConfig {
|
||||
*/
|
||||
private NamingConvention namingConvention = new UnderscoreNamingConvention();
|
||||
|
||||
/**
|
||||
* Naming convention used in DDL generation for primary keys, foreign keys etc.
|
||||
*/
|
||||
private DbConstraintNaming constraintNaming = new DbConstraintNaming();
|
||||
|
||||
/**
|
||||
* Behaviour of updates in JDBC batch to by default include all properties.
|
||||
*/
|
||||
@@ -415,10 +418,6 @@ public class ServerConfig {
|
||||
|
||||
private ServerCachePlugin serverCachePlugin;
|
||||
|
||||
private boolean collectQueryStatsByNode = true;
|
||||
|
||||
private boolean collectQueryOrigins = true;
|
||||
|
||||
/**
|
||||
* The default PersistenceContextScope used if one is not explicitly set on a query.
|
||||
*/
|
||||
@@ -493,6 +492,11 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean collectQueryPlans;
|
||||
|
||||
/**
|
||||
* The default threshold in micros for collecting query plans.
|
||||
*/
|
||||
private long collectQueryPlanThresholdMicros = Long.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* The time in millis used to determine when a query is alerted for being slow.
|
||||
*/
|
||||
@@ -1605,14 +1609,14 @@ public class ServerConfig {
|
||||
* Return the constraint naming convention used in DDL generation.
|
||||
*/
|
||||
public DbConstraintNaming getConstraintNaming() {
|
||||
return constraintNaming;
|
||||
return platformConfig.getConstraintNaming();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the constraint naming convention used in DDL generation.
|
||||
*/
|
||||
public void setConstraintNaming(DbConstraintNaming constraintNaming) {
|
||||
this.constraintNaming = constraintNaming;
|
||||
platformConfig.setConstraintNaming(constraintNaming);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2281,12 +2285,18 @@ public class ServerConfig {
|
||||
* server.
|
||||
*/
|
||||
public void addClass(Class<?> cls) {
|
||||
if (classes == null) {
|
||||
classes = new ArrayList<>();
|
||||
}
|
||||
classes.add(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all the classes (typically entity classes).
|
||||
*/
|
||||
public void addAll(List<Class<?>> classList) {
|
||||
if (classList != null && !classList.isEmpty()) {
|
||||
classes.addAll(classList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a package to search for entities via class path search.
|
||||
* <p>
|
||||
@@ -2294,9 +2304,6 @@ public class ServerConfig {
|
||||
* </p>
|
||||
*/
|
||||
public void addPackage(String packageName) {
|
||||
if (packages == null) {
|
||||
packages = new ArrayList<>();
|
||||
}
|
||||
packages.add(packageName);
|
||||
}
|
||||
|
||||
@@ -2418,52 +2425,6 @@ public class ServerConfig {
|
||||
this.updateAllPropertiesInBatch = updateAllPropertiesInBatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if query statistics should be collected by ObjectGraphNode.
|
||||
*/
|
||||
public boolean isCollectQueryStatsByNode() {
|
||||
return collectQueryStatsByNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to collection query execution statistics by ObjectGraphNode.
|
||||
* <p>
|
||||
* These statistics can be used to highlight code/query 'origin points' that result in lots of lazy loading.
|
||||
* </p>
|
||||
* <p>
|
||||
* It is considered safe/fine to have this set to true for production.
|
||||
* </p>
|
||||
* <p>
|
||||
* This information can be later retrieved via {@link MetaInfoManager}.
|
||||
* </p>
|
||||
*
|
||||
* @see MetaInfoManager
|
||||
*/
|
||||
public void setCollectQueryStatsByNode(boolean collectQueryStatsByNode) {
|
||||
this.collectQueryStatsByNode = collectQueryStatsByNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if query plans should also collect their 'origins'. This means for a given query plan you
|
||||
* can identify the code/origin points where this query resulted from including lazy loading origins.
|
||||
*/
|
||||
public boolean isCollectQueryOrigins() {
|
||||
return collectQueryOrigins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if query plans should collect their 'origin' points. This means for a given query plan you
|
||||
* can identify the code/origin points where this query resulted from including lazy loading origins.
|
||||
* <p>
|
||||
* This information can be later retrieved via {@link MetaInfoManager}.
|
||||
* </p>
|
||||
*
|
||||
* @see MetaInfoManager
|
||||
*/
|
||||
public void setCollectQueryOrigins(boolean collectQueryOrigins) {
|
||||
this.collectQueryOrigins = collectQueryOrigins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource directory.
|
||||
*/
|
||||
@@ -2889,12 +2850,14 @@ public class ServerConfig {
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
|
||||
maxCallStack = p.getInt("maxCallStack", maxCallStack);
|
||||
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
|
||||
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
|
||||
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
|
||||
slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis);
|
||||
collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans);
|
||||
collectQueryPlanThresholdMicros = p.getLong("collectQueryPlanThresholdMicros", collectQueryPlanThresholdMicros);
|
||||
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
enabledL2Regions = p.get("enabledL2Regions", enabledL2Regions);
|
||||
@@ -2921,9 +2884,6 @@ public class ServerConfig {
|
||||
String packagesProp = p.get("search.packages", p.get("packages", null));
|
||||
packages = getSearchList(packagesProp, packages);
|
||||
|
||||
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode);
|
||||
collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins);
|
||||
|
||||
skipCacheAfterWrite = p.getBoolean("skipCacheAfterWrite", skipCacheAfterWrite);
|
||||
updateAllPropertiesInBatch = p.getBoolean("updateAllPropertiesInBatch", updateAllPropertiesInBatch);
|
||||
|
||||
@@ -3016,20 +2976,20 @@ public class ServerConfig {
|
||||
return classes;
|
||||
}
|
||||
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
List<Class<?>> classList = new ArrayList<>();
|
||||
|
||||
String[] split = StringHelper.splitNames(classNames);
|
||||
for (String cn : split) {
|
||||
if (!"class".equalsIgnoreCase(cn)) {
|
||||
try {
|
||||
classes.add(Class.forName(cn));
|
||||
classList.add(Class.forName(cn));
|
||||
} catch (ClassNotFoundException e) {
|
||||
String msg = "Error registering class [" + cn + "] from [" + classNames + "]";
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
return classList;
|
||||
}
|
||||
|
||||
private List<String> getSearchList(String searchNames, List<String> defaultValue) {
|
||||
@@ -3283,6 +3243,20 @@ public class ServerConfig {
|
||||
this.collectQueryPlans = collectQueryPlans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query plan collection threshold in microseconds.
|
||||
*/
|
||||
public long getCollectQueryPlanThresholdMicros() {
|
||||
return collectQueryPlanThresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query plan collection threshold in microseconds.
|
||||
*/
|
||||
public void setCollectQueryPlanThresholdMicros(long collectQueryPlanThresholdMicros) {
|
||||
this.collectQueryPlanThresholdMicros = collectQueryPlanThresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if metrics should be dumped when the server is shutdown.
|
||||
*/
|
||||
@@ -3313,6 +3287,17 @@ public class ServerConfig {
|
||||
this.dumpMetricsOptions = dumpMetricsOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if entity classes should be loaded and registered via ModuleInfoLoader.
|
||||
* <p>
|
||||
* When false we either register entity classes via application code or use classpath
|
||||
* scanning to find and register entity classes.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isAutoLoadModuleInfo() {
|
||||
return loadModuleInfo && classes.isEmpty();
|
||||
}
|
||||
|
||||
public enum UuidVersion {
|
||||
VERSION4,
|
||||
VERSION1,
|
||||
|
||||
@@ -29,6 +29,8 @@ public class DbPlatformTypeMapping {
|
||||
|
||||
private static final DbPlatformType INET_NATIVE = new DbPlatformType("inet", false);
|
||||
private static final DbPlatformType INET_VARCHAR = new DbPlatformType("varchar", 50);
|
||||
private static final DbPlatformType CIDR_NATIVE = new DbPlatformType("cidr", false);
|
||||
private static final DbPlatformType CIDR_VARCHAR = new DbPlatformType("varchar", 50);
|
||||
|
||||
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
|
||||
@SuppressWarnings("unused")
|
||||
@@ -110,6 +112,7 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
put(DbType.INET, INET_NATIVE);
|
||||
put(DbType.CIDR, CIDR_NATIVE);
|
||||
|
||||
} else {
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
|
||||
@@ -126,6 +129,7 @@ public class DbPlatformTypeMapping {
|
||||
// default to native UUID and override on platform configure()
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
put(DbType.INET, INET_VARCHAR);
|
||||
put(DbType.CIDR, CIDR_VARCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public enum DbType {
|
||||
|
||||
UUID(ExtraDbTypes.UUID),
|
||||
INET(ExtraDbTypes.INET),
|
||||
CDIR(ExtraDbTypes.CDIR),
|
||||
CIDR(ExtraDbTypes.CIDR),
|
||||
|
||||
POINT(ExtraDbTypes.POINT),
|
||||
POLYGON(ExtraDbTypes.POLYGON),
|
||||
|
||||
@@ -41,7 +41,7 @@ public interface ExtraDbTypes {
|
||||
int JSONBlob = 5005;
|
||||
|
||||
int INET = 5020;
|
||||
int CDIR = 5021;
|
||||
int CIDR = 5021;
|
||||
|
||||
/**
|
||||
* Geo Point
|
||||
|
||||
@@ -12,9 +12,10 @@ import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Database sequence based IdGenerator.
|
||||
@@ -42,7 +43,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
protected final BackgroundExecutor backgroundExecutor;
|
||||
|
||||
protected final ArrayList<Long> idList = new ArrayList<>(50);
|
||||
protected final NavigableSet<Long> idList = new TreeSet<>();
|
||||
|
||||
protected final int allocationSize;
|
||||
|
||||
@@ -97,15 +98,13 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
@Override
|
||||
public Object nextId(Transaction t) {
|
||||
synchronized (monitor) {
|
||||
|
||||
int size = idList.size();
|
||||
if (size > 0) {
|
||||
maybeLoadMoreInBackground(size);
|
||||
} else {
|
||||
loadMore(allocationSize);
|
||||
}
|
||||
|
||||
return idList.remove(0);
|
||||
return idList.pollFirst();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ClickHousePlatform extends DatabasePlatform {
|
||||
|
||||
dbTypeMap.put(DbType.UUID, new DbPlatformType("UUID", false));
|
||||
dbTypeMap.put(DbType.INET, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.CDIR, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.CIDR, new DbPlatformType("String", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -65,6 +65,8 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.BLOB, new MySqlBlob());
|
||||
dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbPlatformType("json", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,7 +51,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
new SqlErrorCodes()
|
||||
.addAcquireLock("55P03")
|
||||
.addDuplicateKey("23505")
|
||||
.addDataIntegrity("23000","23502","23503","23514")
|
||||
.addDataIntegrity("23000", "23502", "23503", "23514")
|
||||
.addSerializableConflict("40001")
|
||||
.build();
|
||||
|
||||
@@ -63,6 +63,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
|
||||
dbTypeMap.put(DbType.INET, new DbPlatformType("inet", false));
|
||||
dbTypeMap.put(DbType.CIDR, new DbPlatformType("cidr", false));
|
||||
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
@@ -127,7 +128,6 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
@Override
|
||||
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
|
||||
|
||||
try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) {
|
||||
statement.setString(1, table);
|
||||
try (ResultSet resultSet = statement.executeQuery()) {
|
||||
@@ -138,18 +138,15 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Return SQL using built in partition helper functions to create some initial partitions.
|
||||
*
|
||||
* <p>
|
||||
* Only use this if extra-ddl doesn't have some initial partitions defined (which it should).
|
||||
*/
|
||||
@Override
|
||||
public String tablePartitionInit(String tableName, PartitionMode mode, String property, String pkey) {
|
||||
if (property == null) {
|
||||
property = "";
|
||||
}
|
||||
if (pkey == null) {
|
||||
pkey = "";
|
||||
}
|
||||
return "select partition('" + mode.name().toLowerCase() + "','" + tableName + "','" + pkey + "','" + property + "',1);";
|
||||
// default partition required pg11 but this is only used for testing but bumped test docker container to pg11 by default
|
||||
return
|
||||
"create table " + tableName + "_default" + " partition of " + tableName + " default;\n" +
|
||||
"select partition('" + mode.name().toLowerCase() + "','" + tableName + "',1);";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.dbmigration;
|
||||
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
@@ -62,11 +62,28 @@ public interface DbMigration {
|
||||
*/
|
||||
void setPathToResources(String pathToResources);
|
||||
|
||||
/**
|
||||
* Set the path where migrations are generated to (which defaults to "dbmigration").
|
||||
* <p>
|
||||
* Normally we only use this when we use Ebean to generate the database migrations
|
||||
* and then use some other tool like FlywayDB to run the migrations.
|
||||
* <p>
|
||||
* Example: with <code>setMigrationPath("db/migration")</code> ... the migrations
|
||||
* are generated into <code>src/resources/db/migration</code>.
|
||||
* <p>
|
||||
* Note that if Ebean migration runner is used we should not use this method but
|
||||
* instead set the migrationPath via a property such that both the migration generator
|
||||
* and migration runner both use the same path.
|
||||
*
|
||||
* @param migrationPath The path that migrations are generated into.
|
||||
*/
|
||||
void setMigrationPath(String migrationPath);
|
||||
|
||||
/**
|
||||
* Set the server to use to determine the current model.
|
||||
* Typically this is not called explicitly.
|
||||
*/
|
||||
void setServer(EbeanServer ebeanServer);
|
||||
void setServer(Database database);
|
||||
|
||||
/**
|
||||
* Set the serverConfig to use. Typically this is not called explicitly.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.event;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Set;
|
||||
* Listen for bulk table events that occur.
|
||||
* <p>
|
||||
* These events can be triggered via
|
||||
* {@link Ebean#externalModification(String, boolean, boolean, boolean)} or
|
||||
* {@link DB#externalModification(String, boolean, boolean, boolean)} or
|
||||
* automatically determined from Ebean bulk update statements.
|
||||
*/
|
||||
public interface BulkTableEventListener {
|
||||
|
||||
@@ -9,9 +9,8 @@ import java.util.List;
|
||||
public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerMetrics {
|
||||
|
||||
private final List<MetaTimedMetric> timed = new ArrayList<>();
|
||||
private final List<MetaQueryMetric> dtoQuery = new ArrayList<>();
|
||||
private final List<MetaOrmQueryMetric> ormQuery = new ArrayList<>();
|
||||
private final List<MetaCountMetric> countMetrics = new ArrayList<>();
|
||||
private final List<MetaQueryMetric> query = new ArrayList<>();
|
||||
private final List<MetaCountMetric> count = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Construct to reset and collect everything.
|
||||
@@ -27,33 +26,19 @@ public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerM
|
||||
super(reset, collectTransactionMetrics, collectQueryMetrics, collectL2Metrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaTimedMetric> getTimedMetrics() {
|
||||
return timed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DTO query metrics.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaQueryMetric> getDtoQueryMetrics() {
|
||||
return dtoQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaOrmQueryMetric> getOrmQueryMetrics() {
|
||||
return ormQuery;
|
||||
public List<MetaQueryMetric> getQueryMetrics() {
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaCountMetric> getCountMetrics() {
|
||||
return countMetrics;
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,16 +48,11 @@ public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerM
|
||||
|
||||
@Override
|
||||
public void visitQuery(MetaQueryMetric metric) {
|
||||
dtoQuery.add(metric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOrmQuery(MetaOrmQueryMetric metric) {
|
||||
ormQuery.add(metric);
|
||||
query.add(metric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCount(MetaCountMetric metric) {
|
||||
countMetrics.add(metric);
|
||||
count.add(metric);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
/**
|
||||
* Count metrics.
|
||||
* Count metrics. For example L2 cache hits.
|
||||
*/
|
||||
public interface MetaCountMetric {
|
||||
|
||||
/**
|
||||
* Return the metric type.
|
||||
*/
|
||||
MetricType getMetricType();
|
||||
|
||||
/**
|
||||
* Return the metric name.
|
||||
*/
|
||||
String getName();
|
||||
public interface MetaCountMetric extends MetaMetric {
|
||||
|
||||
/**
|
||||
* Return the total count.
|
||||
|
||||
@@ -17,9 +17,21 @@ public interface MetaInfoManager {
|
||||
ServerMetrics collectMetrics();
|
||||
|
||||
/**
|
||||
* Collect query plans.
|
||||
* Collect the metrics in raw JSON form.
|
||||
* <pre>{@code
|
||||
*
|
||||
* String metricsJson = database.getMetaInfoManager()
|
||||
* .collectMetricsAsJson()
|
||||
* .json();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
List<MetaQueryPlan> collectQueryPlans(QueryPlanRequest request);
|
||||
ServerMetricsAsJson collectMetricsAsJson();
|
||||
|
||||
/**
|
||||
* Return the metrics as a list of MetricData.
|
||||
*/
|
||||
List<MetricData> collectMetricsAsData();
|
||||
|
||||
/**
|
||||
* Visit the metrics resetting and collecting/reporting as desired.
|
||||
@@ -38,15 +50,20 @@ public interface MetaInfoManager {
|
||||
void resetAllMetrics();
|
||||
|
||||
/**
|
||||
* Collect and return the ObjectGraphNode statistics.
|
||||
* Initiate query plan collection by turning on "bind capture" on matching query plans.
|
||||
* <p>
|
||||
* These show query executions based on an origin point and relative path.
|
||||
* This is used to look at the amount of lazy loading occurring for a given
|
||||
* query origin point and highlight potential for tuning a query.
|
||||
* </p>
|
||||
* Also refer to ServerConfig collectQueryPlans that needs to be set to true
|
||||
* and collectQueryPlanThresholdMicros which is a global defaults that can also
|
||||
* initiate query plan capture.
|
||||
*
|
||||
* @param reset Set to true to reset the underlying statistics after collection.
|
||||
* @return The query plans that have had bind capture turned on by this request.
|
||||
*/
|
||||
List<MetaOrmQueryNode> collectNodeStatistics(boolean reset);
|
||||
List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest);
|
||||
|
||||
/**
|
||||
* Collect query plans in the foreground.
|
||||
*/
|
||||
List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
/**
|
||||
* Metrics collected by Ebean including timed metrics and counters.
|
||||
*/
|
||||
public interface MetaMetric {
|
||||
|
||||
/**
|
||||
* Return the metric type.
|
||||
*/
|
||||
MetricType getMetricType();
|
||||
|
||||
/**
|
||||
* Return the metric name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Query execution statistics for Orm queries.
|
||||
*/
|
||||
public interface MetaOrmQueryMetric extends MetaQueryMetric {
|
||||
|
||||
/**
|
||||
* Return true if this query plan was tuned by AutoTune.
|
||||
*/
|
||||
boolean isAutoTuned();
|
||||
|
||||
/**
|
||||
* Return the hash of the sql.
|
||||
*/
|
||||
String getSqlHash();
|
||||
|
||||
/**
|
||||
* Return the time of the last query executed using this plan.
|
||||
*/
|
||||
long getLastQueryTime();
|
||||
|
||||
/**
|
||||
* Return the 'origin' points and paths that resulted in the query being
|
||||
* executed and the associated number of times the query was executed via that
|
||||
* path.
|
||||
* <p>
|
||||
* This includes direct and lazy loading paths.
|
||||
* </p>
|
||||
*/
|
||||
List<MetaOrmQueryOrigin> getOrigins();
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
|
||||
/**
|
||||
* Statistics for query execution based on object graph origin and paths.
|
||||
* <p>
|
||||
* These statistics can be used to identify origin queries that result in lots
|
||||
* of lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public interface MetaOrmQueryNode {
|
||||
|
||||
/**
|
||||
* Return the ObjectGraphNode which has the origin point and relative path.
|
||||
*/
|
||||
ObjectGraphNode getNode();
|
||||
|
||||
/**
|
||||
* Return the startTime of statistics collection.
|
||||
*/
|
||||
long getStartTime();
|
||||
|
||||
/**
|
||||
* Return the total count of queries executed for this node.
|
||||
*/
|
||||
long getCount();
|
||||
|
||||
/**
|
||||
* Return the total time of queries executed for this node.
|
||||
*/
|
||||
long getTotalTime();
|
||||
|
||||
/**
|
||||
* Return the total beans loaded by queries for this node.
|
||||
*/
|
||||
long getTotalBeans();
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
|
||||
/**
|
||||
* Holds a query 'origin' point and count for the number of queries executed for
|
||||
* this 'origin'.
|
||||
* <p>
|
||||
* This basically points to the bit of original code and query that results in
|
||||
* this query directly or via lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public interface MetaOrmQueryOrigin {
|
||||
|
||||
/**
|
||||
* The 'origin' and path which this query belongs to.
|
||||
* <p>
|
||||
* For lazy loading queries this points to the original query and associated
|
||||
* navigation path that resulted in this query being executed.
|
||||
* </p>
|
||||
*/
|
||||
ObjectGraphNode getObjectGraphNode();
|
||||
|
||||
/**
|
||||
* The number of times a query was fired for this node since the counter was
|
||||
* last reset.
|
||||
*/
|
||||
long getCount();
|
||||
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
/**
|
||||
* Query execution metrics.
|
||||
*/
|
||||
@@ -17,14 +15,14 @@ public interface MetaQueryMetric extends MetaTimedMetric {
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* The actual SQL of the query.
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Return the hash of the plan.
|
||||
*/
|
||||
String getHash();
|
||||
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ public interface MetaQueryPlan {
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Return the hash of the sql.
|
||||
* Return the hash of the plan.
|
||||
*/
|
||||
String getSqlHash();
|
||||
String getHash();
|
||||
|
||||
/**
|
||||
* Return a description of the bind values.
|
||||
|
||||
@@ -4,28 +4,13 @@ package io.ebean.meta;
|
||||
/**
|
||||
* Timed execution statistics.
|
||||
*/
|
||||
public interface MetaTimedMetric {
|
||||
|
||||
/**
|
||||
* Return the metric type.
|
||||
*/
|
||||
MetricType getMetricType();
|
||||
|
||||
/**
|
||||
* Return the metric name.
|
||||
*/
|
||||
String getName();
|
||||
public interface MetaTimedMetric extends MetaMetric {
|
||||
|
||||
/**
|
||||
* Return the metric location if defined.
|
||||
*/
|
||||
String getLocation();
|
||||
|
||||
/**
|
||||
* Return the time the counters started from.
|
||||
*/
|
||||
long getStartTime();
|
||||
|
||||
/**
|
||||
* Return the total count.
|
||||
*/
|
||||
@@ -47,9 +32,11 @@ public interface MetaTimedMetric {
|
||||
long getMean();
|
||||
|
||||
/**
|
||||
* Return the total beans or rows processed or loaded.
|
||||
*
|
||||
* This will be 0 if the metric isn't a query plan (like transaction execution statistics).
|
||||
* Return true if this is the first metrics collection for this query.
|
||||
* <p>
|
||||
* This can be used to suppress including the SQL and location from metrics
|
||||
* content.
|
||||
* </p>
|
||||
*/
|
||||
long getBeanCount();
|
||||
boolean initialCollection();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
/**
|
||||
* An individual metric.
|
||||
*/
|
||||
public class MetricData {
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
private String hash;
|
||||
private String loc;
|
||||
private String sql;
|
||||
|
||||
private Long count;
|
||||
private Long mean;
|
||||
private Long max;
|
||||
private Long total;
|
||||
|
||||
public MetricData(String name, String type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public MetricData() {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public void setHash(String hash) {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public String getLoc() {
|
||||
return loc;
|
||||
}
|
||||
|
||||
public void setLoc(String loc) {
|
||||
this.loc = loc;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public void setSql(String sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public Long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Long count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Long getMean() {
|
||||
return mean;
|
||||
}
|
||||
|
||||
public void setMean(Long mean) {
|
||||
this.mean = mean;
|
||||
}
|
||||
|
||||
public Long getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(Long max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public Long getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(Long total) {
|
||||
this.total = total;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,11 @@ public enum MetricType {
|
||||
*/
|
||||
TXN,
|
||||
|
||||
/**
|
||||
* ORM Insert Update or Delete.
|
||||
*/
|
||||
IUD,
|
||||
|
||||
/**
|
||||
* ORM queries.
|
||||
*/
|
||||
|
||||
@@ -40,11 +40,6 @@ public interface MetricVisitor {
|
||||
*/
|
||||
void visitQuery(MetaQueryMetric metric);
|
||||
|
||||
/**
|
||||
* Visit ORM query metrics.
|
||||
*/
|
||||
void visitOrmQuery(MetaOrmQueryMetric metric);
|
||||
|
||||
/**
|
||||
* Visit a Counter metric.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Initiate query plan collection for plans by their hash or all query plans.
|
||||
*/
|
||||
public class QueryPlanInit {
|
||||
|
||||
private boolean all;
|
||||
|
||||
private Set<String> hashes = new HashSet<>();
|
||||
|
||||
private long thresholdMicros;
|
||||
|
||||
/**
|
||||
* Return true if this initiates bind collection on all query plans.
|
||||
*/
|
||||
public boolean isAll() {
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to initiate bind collection on all query plans.
|
||||
*/
|
||||
public void setAll(boolean all) {
|
||||
this.all = all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query execution time threshold which must be exceeded to initiate
|
||||
* query plan collection.
|
||||
*/
|
||||
public long getThresholdMicros() {
|
||||
return thresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query execution time threshold which must be exceeded to initiate
|
||||
* query plan collection.
|
||||
*/
|
||||
public void setThresholdMicros(long thresholdMicros) {
|
||||
this.thresholdMicros = thresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query plan should be initiated based on it's hash.
|
||||
*/
|
||||
public boolean includeHash(String hash) {
|
||||
return all || hashes.contains(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specific hashes that we want to collect query plans on.
|
||||
*/
|
||||
public Set<String> getHashes() {
|
||||
return hashes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specific hashes that we want to collect query plans on.
|
||||
*/
|
||||
public void setHashes(Set<String> hashes) {
|
||||
this.hashes = hashes;
|
||||
}
|
||||
}
|
||||
@@ -1,97 +1,66 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Request used to capture query plans.
|
||||
*/
|
||||
public class QueryPlanRequest {
|
||||
|
||||
private final List<MetaQueryPlan> plans = new ArrayList<>();
|
||||
|
||||
private Connection connection;
|
||||
|
||||
private boolean store;
|
||||
|
||||
private long since;
|
||||
|
||||
private Set<Class<?>> includedBeanTypes;
|
||||
private int maxCount;
|
||||
|
||||
private Set<String> includedLabels;
|
||||
|
||||
public List<MetaQueryPlan> getPlans() {
|
||||
return plans;
|
||||
}
|
||||
private long maxTimeMillis;
|
||||
|
||||
/**
|
||||
* Return the connection to use to capture the query plans.
|
||||
*/
|
||||
public Connection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection to use to capture the query plans.
|
||||
*/
|
||||
public void setConnection(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the captured query plan is stored.
|
||||
*/
|
||||
public boolean isStore() {
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to store the captured query plan.
|
||||
*/
|
||||
public void setStore(boolean store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the epoch time after which the query plan was capture (to be included).
|
||||
* Return the epoch time in millis for minimum bind capture time.
|
||||
* <p>
|
||||
* When set this ensures that the bind values used to get the query plan
|
||||
* have been around for a while (e.g. 5 mins) and so reasonably represent
|
||||
* bind values that match the slowest execution for this query plan.
|
||||
*/
|
||||
public long getSince() {
|
||||
return since;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the epoch time after which the query plan was captured.
|
||||
* <p>
|
||||
* This is used to only capture plans that have changed since a given time (like the time of last capture).
|
||||
* </p>
|
||||
* Set the epoch time (e.g. 5 mins ago) such that the query bind values
|
||||
* reasonably represent bind values that match the slowest execution for this query plan.
|
||||
*
|
||||
* @param since The time after which the query plan was captured to be included
|
||||
* @param since The minimum age of the bind values capture.
|
||||
*/
|
||||
public void setSince(long since) {
|
||||
this.since = since;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process consume the query plan.
|
||||
* Return the maximum number of plans to capture.
|
||||
*/
|
||||
public void process(MetaQueryPlan plan) {
|
||||
plans.add(plan);
|
||||
public int getMaxCount() {
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean type should be included in the query plan capture.
|
||||
* Set the maximum number of plans to capture.
|
||||
*/
|
||||
public boolean includeType(Class<?> beanType) {
|
||||
return includedBeanTypes == null || includedBeanTypes.isEmpty() || includedBeanTypes.contains(beanType);
|
||||
public void setMaxCount(int maxCount) {
|
||||
this.maxCount = maxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the label should be included in the query plan capture.
|
||||
* Return the maximum amount of time we want to use to capture plans.
|
||||
* <p>
|
||||
* Query plan collection will stop once this time is exceeded.
|
||||
*/
|
||||
public boolean includeLabel(String label) {
|
||||
return includedLabels == null || includedLabels.isEmpty() || includedLabels.contains(label);
|
||||
public long getMaxTimeMillis() {
|
||||
return maxTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum amount of time we want to use to capture plans.
|
||||
* <p>
|
||||
* Query plan collection will stop once this time is exceeded.
|
||||
*/
|
||||
public void setMaxTimeMillis(long maxTimeMillis) {
|
||||
this.maxTimeMillis = maxTimeMillis;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,9 @@ public interface ServerMetrics {
|
||||
List<MetaTimedMetric> getTimedMetrics();
|
||||
|
||||
/**
|
||||
* Return the DTO query metrics.
|
||||
* Return the query metrics.
|
||||
*/
|
||||
List<MetaQueryMetric> getDtoQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
List<MetaOrmQueryMetric> getOrmQueryMetrics();
|
||||
List<MetaQueryMetric> getQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return the Counter metrics.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Collect the metrics in raw JSON form.
|
||||
*/
|
||||
public interface ServerMetricsAsJson {
|
||||
|
||||
/**
|
||||
* Set to false to exclude profile location and sql.
|
||||
*/
|
||||
ServerMetricsAsJson withExtraAttributes(boolean withLocation);
|
||||
|
||||
/**
|
||||
* Set to false to exclude SQL hash.
|
||||
*/
|
||||
ServerMetricsAsJson withHash(boolean withHash);
|
||||
|
||||
/**
|
||||
* Set the sort property - see SortMetric
|
||||
* @see SortMetric
|
||||
*/
|
||||
ServerMetricsAsJson withSort(Comparator<MetaTimedMetric> sortBy);
|
||||
|
||||
/**
|
||||
* Set the new line character to use.
|
||||
*/
|
||||
ServerMetricsAsJson withNewLine(boolean withNewLine);
|
||||
|
||||
/**
|
||||
* Set to include a heading of the database name.
|
||||
* <p>
|
||||
* When this is false the metrics are written without json array start or array end.
|
||||
*/
|
||||
ServerMetricsAsJson withHeader(boolean withHeader);
|
||||
|
||||
/**
|
||||
* Collect and write metrics as JSON to the given buffer.
|
||||
*/
|
||||
void write(Appendable buffer);
|
||||
|
||||
/**
|
||||
* Return the metrics in raw JSON.
|
||||
*/
|
||||
String json();
|
||||
}
|
||||
@@ -13,20 +13,15 @@ public interface TimedMetric {
|
||||
void add(long micros);
|
||||
|
||||
/**
|
||||
* Add a time event with the number of loaded beans or rows.
|
||||
* Add a time event for a batch of beans.
|
||||
*/
|
||||
void add(long micros, long beans);
|
||||
void addBatchSince(long startNanos, int batch);
|
||||
|
||||
/**
|
||||
* Add a time event given the start nanos.
|
||||
*/
|
||||
void addSinceNanos(long startNanos);
|
||||
|
||||
/**
|
||||
* Add a time event given the start nanos and bean count.
|
||||
*/
|
||||
void addSinceNanos(long startNanos, long beans);
|
||||
|
||||
/**
|
||||
* Return true if there are no metrics collected since the last collection.
|
||||
*/
|
||||
|
||||
@@ -12,21 +12,11 @@ public interface TimedMetricMap {
|
||||
*/
|
||||
void addSinceNanos(String key, long startNanos);
|
||||
|
||||
/**
|
||||
* Add a time event given the start nanos and beans.
|
||||
*/
|
||||
void addSinceNanos(String key, long startNanos, int beans);
|
||||
|
||||
/**
|
||||
* Add an execution for the given key.
|
||||
*/
|
||||
void add(String key, long exeMicros);
|
||||
|
||||
/**
|
||||
* Add an execution for the given key including row/bean count.
|
||||
*/
|
||||
void add(String key, long exeMicros, int rows);
|
||||
|
||||
/**
|
||||
* Visit the metric.
|
||||
*/
|
||||
|
||||
@@ -11,4 +11,9 @@ public interface TimedMetricStats extends MetaTimedMetric {
|
||||
* Additionally set the location.
|
||||
*/
|
||||
void setLocation(String location);
|
||||
|
||||
/**
|
||||
* Override the name based on profile location.
|
||||
*/
|
||||
void setName(String name);
|
||||
}
|
||||
|
||||
@@ -149,6 +149,13 @@ public interface JsonContext {
|
||||
*/
|
||||
String toJson(Object value) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return the bean or collection as JSON string in pretty format.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
String toJsonPretty(Object value) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection in JSON format to the writer.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
import io.ebean.metric.TimedMetric;
|
||||
|
||||
/**
|
||||
* Extra metrics collected to measure internal behaviour.
|
||||
*/
|
||||
public class ExtraMetrics {
|
||||
|
||||
private final TimedMetric bindCapture;
|
||||
private final TimedMetric planCollect;
|
||||
|
||||
/**
|
||||
* Create the extra metrics.
|
||||
*/
|
||||
public ExtraMetrics() {
|
||||
final MetricFactory factory = MetricFactory.get();
|
||||
this.bindCapture = factory.createTimedMetric(MetricType.ORM, "ebean.queryplan.bindcapture");
|
||||
this.planCollect = factory.createTimedMetric(MetricType.ORM, "ebean.queryplan.collect");
|
||||
}
|
||||
|
||||
/**
|
||||
* Timed metric for bind capture used with query plan collection.
|
||||
*/
|
||||
public TimedMetric getBindCapture() {
|
||||
return bindCapture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timed metric for query plan collection.
|
||||
*/
|
||||
public TimedMetric getPlanCollect() {
|
||||
return planCollect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the metrics.
|
||||
*/
|
||||
public void visitMetrics(MetricVisitor visitor) {
|
||||
bindCapture.visit(visitor);
|
||||
planCollect.visit(visitor);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.TxScope;
|
||||
|
||||
/**
|
||||
@@ -28,7 +28,7 @@ public class HelpScopeTrans {
|
||||
}
|
||||
|
||||
private static SpiEbeanServer server() {
|
||||
return (SpiEbeanServer) Ebean.getDefaultServer();
|
||||
return (SpiEbeanServer) DB.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,86 +1,17 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
|
||||
import io.ebean.Pairs;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Natural key entry with name value pairs for each of the properties making up the key.
|
||||
* An entry for natural key lookup.
|
||||
*/
|
||||
public class NaturalKeyEntry {
|
||||
|
||||
private final Map<String,Object> map = new HashMap<>();
|
||||
private final Object key;
|
||||
private Object inValue;
|
||||
|
||||
/**
|
||||
* Used when query query just has a series of EQ expressions (no IN clause).
|
||||
*/
|
||||
public NaturalKeyEntry(String[] naturalKey, List<NaturalKeyEq> eqList) {
|
||||
load(eqList);
|
||||
this.key = calculateKey(naturalKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create when query uses an IN clause.
|
||||
*/
|
||||
public NaturalKeyEntry(String[] naturalKey, List<NaturalKeyEq> eqList, String inProperty, Object inValue) {
|
||||
load(eqList);
|
||||
if (inProperty != null) {
|
||||
map.put(inProperty, inValue);
|
||||
this.inValue = inValue;
|
||||
}
|
||||
this.key = calculateKey(naturalKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create when query uses an IN PAIRS clause.
|
||||
*/
|
||||
public NaturalKeyEntry(String[] naturalKey, List<NaturalKeyEq> eqList,
|
||||
String inMapProperty0, String inMapProperty1, Pairs.Entry pair) {
|
||||
load(eqList);
|
||||
map.put(inMapProperty0, pair.getA());
|
||||
map.put(inMapProperty1, pair.getB());
|
||||
this.inValue = pair;
|
||||
this.key = calculateKey(naturalKey);
|
||||
}
|
||||
|
||||
private void load(List<NaturalKeyEq> eqList) {
|
||||
if (eqList != null) {
|
||||
for (NaturalKeyEq eq : eqList) {
|
||||
map.put(eq.property, eq.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object calculateKey(String[] naturalKey) {
|
||||
|
||||
if (naturalKey.length == 1) {
|
||||
return map.get(naturalKey[0]);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String key : naturalKey) {
|
||||
sb.append(map.get(key)).append(";");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
public interface NaturalKeyEntry {
|
||||
|
||||
/**
|
||||
* Return the natural cache key (String concatenation of values).
|
||||
*/
|
||||
public Object key() {
|
||||
return key;
|
||||
}
|
||||
String key();
|
||||
|
||||
/**
|
||||
* Return the inValue (used to remove from IN clause of original query).
|
||||
*/
|
||||
public Object getInValue() {
|
||||
return inValue;
|
||||
}
|
||||
Object getInValue();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
|
||||
import io.ebean.Pairs;
|
||||
import io.ebeaninternal.server.deploy.BeanNaturalKey;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Natural key entry with name value pairs for each of the properties making up the key.
|
||||
*/
|
||||
class NaturalKeyEntryBasic implements NaturalKeyEntry {
|
||||
|
||||
private final Map<String,Object> map = new HashMap<>();
|
||||
private final String key;
|
||||
private Object inValue;
|
||||
|
||||
/**
|
||||
* Used when query query just has a series of EQ expressions (no IN clause).
|
||||
*/
|
||||
NaturalKeyEntryBasic(BeanNaturalKey naturalKey, List<NaturalKeyEq> eqList) {
|
||||
load(eqList);
|
||||
this.key = calculateKey(naturalKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create when query uses an IN clause.
|
||||
*/
|
||||
NaturalKeyEntryBasic(BeanNaturalKey naturalKey, List<NaturalKeyEq> eqList, String inProperty, Object inValue) {
|
||||
load(eqList);
|
||||
if (inProperty != null) {
|
||||
map.put(inProperty, inValue);
|
||||
this.inValue = inValue;
|
||||
}
|
||||
this.key = calculateKey(naturalKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create when query uses an IN PAIRS clause.
|
||||
*/
|
||||
NaturalKeyEntryBasic(BeanNaturalKey naturalKey, List<NaturalKeyEq> eqList,
|
||||
String inMapProperty0, String inMapProperty1, Pairs.Entry pair) {
|
||||
load(eqList);
|
||||
map.put(inMapProperty0, pair.getA());
|
||||
map.put(inMapProperty1, pair.getB());
|
||||
this.inValue = pair;
|
||||
this.key = calculateKey(naturalKey);
|
||||
}
|
||||
|
||||
private void load(List<NaturalKeyEq> eqList) {
|
||||
if (eqList != null) {
|
||||
for (NaturalKeyEq eq : eqList) {
|
||||
map.put(eq.property, eq.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String calculateKey(BeanNaturalKey naturalKey) {
|
||||
return naturalKey.calculateKey(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getInValue() {
|
||||
return inValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
class NaturalKeyEntrySimple implements NaturalKeyEntry {
|
||||
|
||||
private final String key;
|
||||
private final Object val;
|
||||
|
||||
NaturalKeyEntrySimple(Object val) {
|
||||
this.key = val.toString();
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getInValue() {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.Pairs;
|
||||
import io.ebeaninternal.server.deploy.BeanNaturalKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
@@ -12,7 +13,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class NaturalKeyQueryData<T> {
|
||||
|
||||
private final String[] naturalKey;
|
||||
private final BeanNaturalKey naturalKey;
|
||||
|
||||
/**
|
||||
* Only one of IN or IN PAIRS is allowed.
|
||||
@@ -34,18 +35,12 @@ public class NaturalKeyQueryData<T> {
|
||||
|
||||
private int hitCount;
|
||||
|
||||
public NaturalKeyQueryData(String[] naturalKey) {
|
||||
public NaturalKeyQueryData(BeanNaturalKey naturalKey) {
|
||||
this.naturalKey = naturalKey;
|
||||
}
|
||||
|
||||
private boolean matchProperty(String propName) {
|
||||
|
||||
for (String key : naturalKey) {
|
||||
if (key.equals(propName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return naturalKey.matchProperty(propName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,37 +103,52 @@ public class NaturalKeyQueryData<T> {
|
||||
|
||||
this.set = new NaturalKeySet();
|
||||
if (inValues != null) {
|
||||
// a findList() with an IN clause so we project
|
||||
// for every IN value a natural key combination
|
||||
for (Object inValue : inValues) {
|
||||
set.add(new NaturalKeyEntry(naturalKey, eqList, inProperty, inValue));
|
||||
}
|
||||
addInValues();
|
||||
} else if (inPairs != null) {
|
||||
// a findList() with an IN Map clause so we project
|
||||
// for every IN value a natural key combination
|
||||
for (Pairs.Entry entry : inPairs) {
|
||||
set.add(new NaturalKeyEntry(naturalKey, eqList, inProperty0, inProperty1, entry));
|
||||
}
|
||||
|
||||
addInPairs();
|
||||
} else {
|
||||
// only one - a findOne()
|
||||
set.add(new NaturalKeyEntry(naturalKey, eqList));
|
||||
addEqualsKey();
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
private void addInPairs() {
|
||||
// a findList() with an IN Map clause so we project
|
||||
// for every IN value a natural key combination
|
||||
for (Pairs.Entry entry : inPairs) {
|
||||
set.add(new NaturalKeyEntryBasic(naturalKey, eqList, inProperty0, inProperty1, entry));
|
||||
}
|
||||
}
|
||||
|
||||
private void addInValues() {
|
||||
if (eqList == null) {
|
||||
// a single property IN expression
|
||||
for (Object inValue : inValues) {
|
||||
set.add(new NaturalKeyEntrySimple(inValue));
|
||||
}
|
||||
} else {
|
||||
// IN expression + EQ expression(s)
|
||||
for (Object inValue : inValues) {
|
||||
set.add(new NaturalKeyEntryBasic(naturalKey, eqList, inProperty, inValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addEqualsKey() {
|
||||
if (eqList.size() == 1) {
|
||||
// a single property EQ expression
|
||||
set.add(new NaturalKeyEntrySimple(eqList.get(0).value));
|
||||
} else {
|
||||
set.add(new NaturalKeyEntryBasic(naturalKey, eqList));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the properties match the natural key properties.
|
||||
*/
|
||||
private boolean matchProperties() {
|
||||
if (naturalKey.length == 1) {
|
||||
// simple single property case
|
||||
if (inProperty != null) {
|
||||
return inProperty.equals(naturalKey[0]);
|
||||
} else {
|
||||
return eqList.get(0).property.equals(naturalKey[0]);
|
||||
}
|
||||
if (naturalKey.isSingleProperty()) {
|
||||
naturalKey.matchSingleProperty((inProperty != null) ? inProperty : eqList.get(0).property);
|
||||
}
|
||||
|
||||
// multiple properties case
|
||||
@@ -157,27 +167,17 @@ public class NaturalKeyQueryData<T> {
|
||||
exprProps.add(eq.property);
|
||||
}
|
||||
}
|
||||
if (exprProps.size() != naturalKey.length) {
|
||||
return false;
|
||||
}
|
||||
for (String key : naturalKey) {
|
||||
if (!exprProps.remove(key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return exprProps.isEmpty();
|
||||
return naturalKey.matchMultiProperties(exprProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that all the natural key properties are defined.
|
||||
*/
|
||||
private boolean expressionCount() {
|
||||
|
||||
int defined = (inValues == null) ? 0 : 1;
|
||||
defined += (inPairs == null) ? 0 : 2;
|
||||
defined += (eqList == null) ? 0 : eqList.size();
|
||||
return defined == naturalKey.length;
|
||||
return defined == naturalKey.length();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@ public class NaturalKeySet {
|
||||
|
||||
private final Map<Object, NaturalKeyEntry> map = new LinkedHashMap<>();
|
||||
|
||||
public NaturalKeySet() {
|
||||
NaturalKeySet() {
|
||||
}
|
||||
|
||||
public int size() {
|
||||
@@ -24,8 +24,7 @@ public class NaturalKeySet {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
public Object getInValue(Object naturalKey) {
|
||||
NaturalKeyEntry entry = map.get(naturalKey);
|
||||
return entry.getInValue();
|
||||
Object getInValue(Object naturalKey) {
|
||||
return map.get(naturalKey).getInValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebeaninternal.server.type.bindcapture.BindCapture;
|
||||
|
||||
class NoopQueryBindCapture implements SpiQueryBindCapture {
|
||||
|
||||
@Override
|
||||
public boolean collectFor(long timeMicros) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBind(BindCapture bindCapture, long timeMicros, long startNanos) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryPlanInit(long thresholdMicros) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class NoopQueryPlanManager implements QueryPlanManager {
|
||||
|
||||
@Override
|
||||
public SpiQueryBindCapture createBindCapture(SpiQueryPlan queryPlan) {
|
||||
return SpiQueryBindCapture.NOOP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlan> collect(QueryPlanRequest request) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manage query plan capture.
|
||||
*/
|
||||
public interface QueryPlanManager {
|
||||
|
||||
QueryPlanManager NOOP = new NoopQueryPlanManager();
|
||||
|
||||
/**
|
||||
* Create the bind capture for the given query plan.
|
||||
*/
|
||||
SpiQueryBindCapture createBindCapture(SpiQueryPlan queryPlan);
|
||||
|
||||
/**
|
||||
* Collect the database query plans.
|
||||
*/
|
||||
List<MetaQueryPlan> collect(QueryPlanRequest request);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
|
||||
/**
|
||||
* Internal database query plan being capture.
|
||||
*/
|
||||
public interface SpiDbQueryPlan extends MetaQueryPlan {
|
||||
|
||||
/**
|
||||
* Extend with queryTimeMicros and captureCount.
|
||||
*/
|
||||
SpiDbQueryPlan with(long queryTimeMicros, long captureCount);
|
||||
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import io.ebean.TxScope;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.BeanLoader;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
@@ -49,11 +48,6 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
|
||||
*/
|
||||
void shutdownManaged();
|
||||
|
||||
/**
|
||||
* Return true if query origins should be collected.
|
||||
*/
|
||||
boolean isCollectQueryOrigins();
|
||||
|
||||
/**
|
||||
* Return true if updates in JDBC batch should include all columns if unspecified on the transaction.
|
||||
*/
|
||||
@@ -201,11 +195,6 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
|
||||
*/
|
||||
boolean isSupportedType(java.lang.reflect.Type genericType);
|
||||
|
||||
/**
|
||||
* Collect query statistics by ObjectGraphNode. Used for Lazy loading reporting.
|
||||
*/
|
||||
void collectQueryStats(ObjectGraphNode objectGraphNode, long loadedBeanCount, long timeMicros);
|
||||
|
||||
/**
|
||||
* Return the ReadAuditLogger to use for logging all read audit events.
|
||||
*/
|
||||
@@ -321,4 +310,9 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
|
||||
* Execute the sql update regardless of transaction batch mode.
|
||||
*/
|
||||
int executeNow(SpiSqlUpdate sqlUpdate);
|
||||
|
||||
/**
|
||||
* Create a query bind capture for the given query plan.
|
||||
*/
|
||||
SpiQueryBindCapture createQueryBindCapture(SpiQueryPlan queryPlan);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebeaninternal.server.type.bindcapture.BindCapture;
|
||||
|
||||
/**
|
||||
* Capture query bind values and with those actual database query plans.
|
||||
*/
|
||||
public interface SpiQueryBindCapture {
|
||||
|
||||
/**
|
||||
* NOOP implementation.
|
||||
*/
|
||||
SpiQueryBindCapture NOOP = new NoopQueryBindCapture();
|
||||
|
||||
/**
|
||||
* Return true if the query just executed should be bind captured to collect
|
||||
* the query plan from (as the query time is large / interesting).
|
||||
*/
|
||||
boolean collectFor(long timeMicros);
|
||||
|
||||
/**
|
||||
* Set the captured bind values that we can use later to collect a query plan.
|
||||
*
|
||||
* @param bindCapture The bind values of the query
|
||||
* @param queryTimeMicros The query execution time
|
||||
* @param startNanos The nanos start of this bind capture
|
||||
*/
|
||||
void setBind(BindCapture bindCapture, long queryTimeMicros, long startNanos);
|
||||
|
||||
/**
|
||||
* Update the threshold micros triggering the bind capture.
|
||||
*/
|
||||
void queryPlanInit(long thresholdMicros);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
/**
|
||||
* The internal ORM "query plan".
|
||||
*/
|
||||
public interface SpiQueryPlan {
|
||||
|
||||
/**
|
||||
* The related entity bean type
|
||||
*/
|
||||
Class<?> getBeanType();
|
||||
|
||||
/**
|
||||
* The plan name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* The hash for the query plan.
|
||||
*/
|
||||
String getHash();
|
||||
|
||||
/**
|
||||
* The SQL for the query plan.
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* The related profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Initiate bind capture with the give threshold.
|
||||
*/
|
||||
void queryPlanInit(long thresholdMicros);
|
||||
|
||||
/**
|
||||
* Return as Database query plan.
|
||||
*
|
||||
* @param bind Description of the bind values used
|
||||
* @param planString The raw database query plan
|
||||
*/
|
||||
SpiDbQueryPlan createMeta(String bind, String planString);
|
||||
|
||||
}
|
||||
@@ -33,4 +33,9 @@ public interface SpiSqlUpdate extends SqlUpdate {
|
||||
* Reset bind position to be ready for another bind execute.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Return a copy of the SqlUpdate with empty bind parameters.
|
||||
*/
|
||||
SpiSqlUpdate copy();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.dbmigration;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
@@ -90,6 +91,8 @@ public class DefaultDbMigration implements DbMigration {
|
||||
|
||||
protected String pathToResources = "src/main/resources";
|
||||
|
||||
protected String migrationPath;
|
||||
|
||||
protected DatabasePlatform databasePlatform;
|
||||
|
||||
private boolean vanillaPlatform;
|
||||
@@ -137,13 +140,18 @@ public class DefaultDbMigration implements DbMigration {
|
||||
this.pathToResources = pathToResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMigrationPath(String migrationPath) {
|
||||
this.migrationPath = migrationPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server to use to determine the current model.
|
||||
* Typically this is not called explicitly.
|
||||
*/
|
||||
@Override
|
||||
public void setServer(EbeanServer ebeanServer) {
|
||||
this.server = (SpiEbeanServer) ebeanServer;
|
||||
public void setServer(Database database) {
|
||||
this.server = (SpiEbeanServer) database;
|
||||
setServerConfig(server.getServerConfig());
|
||||
}
|
||||
|
||||
@@ -671,7 +679,7 @@ public class DefaultDbMigration implements DbMigration {
|
||||
*/
|
||||
private void setDefaults() {
|
||||
if (server == null) {
|
||||
setServer(Ebean.getDefaultServer());
|
||||
setServer(DB.getDefault());
|
||||
}
|
||||
if (vanillaPlatform || databasePlatform == null) {
|
||||
// not explicitly set so use the platform of the server
|
||||
@@ -684,6 +692,9 @@ public class DefaultDbMigration implements DbMigration {
|
||||
if (applyPrefix != null) {
|
||||
migrationConfig.setApplyPrefix(applyPrefix);
|
||||
}
|
||||
if (migrationPath != null) {
|
||||
migrationConfig.setMigrationPath(migrationPath);
|
||||
}
|
||||
if (header != null) {
|
||||
migrationConfig.setDdlHeader(header);
|
||||
}
|
||||
|
||||
@@ -105,9 +105,9 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
@Override
|
||||
public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(dropIndex(uniqueConstraintName, tableName)).append(";\n");
|
||||
sb.append("IF (OBJECT_ID('").append(maxConstraintName(uniqueConstraintName)).append("', 'UQ') IS NOT NULL) ");
|
||||
sb.append(super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName)).append(";\n");
|
||||
sb.append(dropIndex(uniqueConstraintName, tableName));
|
||||
sb.append(super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName));
|
||||
return sb.toString();
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package io.ebeaninternal.dbmigration.model;
|
||||
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
|
||||
import io.ebeaninternal.dbmigration.migration.ChangeSet;
|
||||
import io.ebeaninternal.dbmigration.model.build.ModelBuildBeanVisitor;
|
||||
import io.ebeaninternal.dbmigration.model.build.ModelBuildContext;
|
||||
@@ -24,9 +24,9 @@ public class CurrentModel {
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
private final DbConstraintNaming constraintNaming;
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
private final DbConstraintNaming constraintNaming;
|
||||
|
||||
private final boolean platformTypes;
|
||||
|
||||
@@ -60,8 +60,8 @@ public class CurrentModel {
|
||||
|
||||
private CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, boolean platformTypes) {
|
||||
this.server = server;
|
||||
this.databasePlatform = server.getDatabasePlatform();
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.maxLength = maxLength(server, constraintNaming);
|
||||
this.platformTypes = platformTypes;
|
||||
this.jaxbPresent = server.getServerConfig().getClassLoadConfig().isJavaxJAXBPresent();
|
||||
}
|
||||
@@ -84,16 +84,6 @@ public class CurrentModel {
|
||||
return read().getPartitionedTables();
|
||||
}
|
||||
|
||||
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
|
||||
|
||||
if (naming.getMaxLength() != null) {
|
||||
return naming.getMaxLength();
|
||||
}
|
||||
|
||||
int maxConstraintNameLength = server.getDatabasePlatform().getMaxConstraintNameLength();
|
||||
return new DefaultConstraintMaxLength(maxConstraintNameLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current model by reading all the bean descriptors and properties.
|
||||
*/
|
||||
@@ -101,7 +91,7 @@ public class CurrentModel {
|
||||
if (model == null) {
|
||||
model = new ModelContainer();
|
||||
|
||||
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength, platformTypes);
|
||||
ModelBuildContext context = new ModelBuildContext(model, databasePlatform, constraintNaming, platformTypes);
|
||||
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
|
||||
VisitAllUsing visit = new VisitAllUsing(visitor, server);
|
||||
visit.visitAllBeans();
|
||||
|
||||
@@ -443,6 +443,10 @@ public class MTable {
|
||||
return partitionMeta;
|
||||
}
|
||||
|
||||
public String getPkName() {
|
||||
return pkName;
|
||||
}
|
||||
|
||||
public void setPkName(String pkName) {
|
||||
this.pkName = pkName;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package io.ebeaninternal.dbmigration.model.build;
|
||||
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbPlatformTypeMapping;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
|
||||
import io.ebeaninternal.dbmigration.model.MColumn;
|
||||
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
@@ -30,17 +32,30 @@ public class ModelBuildContext {
|
||||
|
||||
private final ModelContainer model;
|
||||
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final DbConstraintNaming constraintNaming;
|
||||
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
|
||||
private final boolean platformTypes;
|
||||
|
||||
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
|
||||
public ModelBuildContext(ModelContainer model, DatabasePlatform databasePlatform, DbConstraintNaming naming, boolean platformTypes) {
|
||||
this.model = model;
|
||||
this.databasePlatform = databasePlatform;
|
||||
this.constraintNaming = naming;
|
||||
this.maxLength = maxLength;
|
||||
this.platformTypes = platformTypes;
|
||||
this.maxLength = maxLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the max length handling for constraint names.
|
||||
*/
|
||||
private DbConstraintNaming.MaxLength maxLength() {
|
||||
if (constraintNaming.getMaxLength() != null) {
|
||||
return constraintNaming.getMaxLength();
|
||||
}
|
||||
return new DefaultConstraintMaxLength(databasePlatform.getMaxConstraintNameLength());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,40 +70,51 @@ public class ModelBuildContext {
|
||||
return constraintNaming.normaliseTable(baseTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take into account max length and quoted identifiers in constraint and index names.
|
||||
*/
|
||||
private String name(String constraintName, int indexCount) {
|
||||
return databasePlatform.convertQuotedIdentifiers(maxLength(constraintName, indexCount));
|
||||
}
|
||||
|
||||
private String maxLength(String constraintName, int indexCount) {
|
||||
return maxLength.maxLength(constraintName, indexCount);
|
||||
}
|
||||
|
||||
public String primaryKeyName(String tableName) {
|
||||
return maxLength(constraintNaming.primaryKeyName(tableName), 0);
|
||||
return name(constraintNaming.primaryKeyName(tableName), 0);
|
||||
}
|
||||
|
||||
public String foreignKeyConstraintName(String tableName, String columnName, int foreignKeyCount) {
|
||||
return maxLength(constraintNaming.foreignKeyConstraintName(tableName, columnName), foreignKeyCount);
|
||||
return name(constraintNaming.foreignKeyConstraintName(tableName, columnName), foreignKeyCount);
|
||||
}
|
||||
|
||||
public String foreignKeyIndexName(String tableName, String[] columns, int indexCount) {
|
||||
return maxLength(constraintNaming.foreignKeyIndexName(tableName, columns), indexCount);
|
||||
return name(constraintNaming.foreignKeyIndexName(tableName, columns), indexCount);
|
||||
}
|
||||
|
||||
public String foreignKeyIndexName(String tableName, String column, int indexCount) {
|
||||
return maxLength(constraintNaming.foreignKeyIndexName(tableName, column), indexCount);
|
||||
return name(constraintNaming.foreignKeyIndexName(tableName, column), indexCount);
|
||||
}
|
||||
|
||||
public String indexName(String tableName, String column, int indexCount) {
|
||||
return maxLength(constraintNaming.indexName(tableName, column), indexCount);
|
||||
return name(constraintNaming.indexName(tableName, column), indexCount);
|
||||
}
|
||||
|
||||
public String indexName(String tableName, String[] columns, int indexCount) {
|
||||
return maxLength(constraintNaming.indexName(tableName, columns), indexCount);
|
||||
return name(constraintNaming.indexName(tableName, columns), indexCount);
|
||||
}
|
||||
|
||||
public String uniqueConstraintName(String tableName, String columnName, int indexCount) {
|
||||
return maxLength(constraintNaming.uniqueConstraintName(tableName, columnName), indexCount);
|
||||
return name(constraintNaming.uniqueConstraintName(tableName, columnName), indexCount);
|
||||
}
|
||||
|
||||
public String uniqueConstraintName(String tableName, String[] columnNames, int indexCount) {
|
||||
return maxLength(constraintNaming.uniqueConstraintName(tableName, columnNames), indexCount);
|
||||
return name(constraintNaming.uniqueConstraintName(tableName, columnNames), indexCount);
|
||||
}
|
||||
|
||||
public String checkConstraintName(String tableName, String columnName, int checkCount) {
|
||||
return maxLength(constraintNaming.checkConstraintName(tableName, columnName), checkCount);
|
||||
return name(constraintNaming.checkConstraintName(tableName, columnName), checkCount);
|
||||
}
|
||||
|
||||
public MTable addTable(MTable table) {
|
||||
@@ -107,10 +133,6 @@ public class ModelBuildContext {
|
||||
model.addIndex(indexName, tableName, columnNames);
|
||||
}
|
||||
|
||||
private String maxLength(String constraintName, int indexCount) {
|
||||
return maxLength.maxLength(constraintName, indexCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the map used to determine the DB specific type
|
||||
* for a given bean property.
|
||||
|
||||
@@ -142,6 +142,7 @@ public class BaseQueryTuner {
|
||||
SpiQuery.Type type = query.getType();
|
||||
switch (type) {
|
||||
case COUNT:
|
||||
case ATTRIBUTE:
|
||||
case ID_LIST:
|
||||
case UPDATE:
|
||||
case DELETE:
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.meta.MetaOrmQueryNode;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* Helper to collect the query execution statistics for a given node.
|
||||
*/
|
||||
public class CObjectGraphNodeStatistics {
|
||||
|
||||
private final ObjectGraphNode node;
|
||||
|
||||
private final LongAdder count = new LongAdder();
|
||||
|
||||
private final LongAdder totalTime = new LongAdder();
|
||||
|
||||
private final LongAdder totalBeans = new LongAdder();
|
||||
|
||||
private final AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
|
||||
|
||||
CObjectGraphNodeStatistics(ObjectGraphNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return count.sum() == 0;
|
||||
}
|
||||
|
||||
public void add(long beanCount, long exeMicros) {
|
||||
count.increment();
|
||||
totalTime.add(exeMicros);
|
||||
totalBeans.add(beanCount);
|
||||
}
|
||||
|
||||
public MetaOrmQueryNode get(boolean reset) {
|
||||
if (reset) {
|
||||
return new Snapshot(node, startTime.getAndSet(System.currentTimeMillis()), count.sumThenReset(),
|
||||
totalTime.sumThenReset(), totalBeans.sumThenReset());
|
||||
} else {
|
||||
return new Snapshot(node, startTime.get(), count.sum(), totalTime.sum(), totalBeans.sum());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Snapshot implements MetaOrmQueryNode {
|
||||
|
||||
private final ObjectGraphNode node;
|
||||
private final long startTime;
|
||||
private final long count;
|
||||
private final long totalTime;
|
||||
private final long totalBeans;
|
||||
|
||||
public Snapshot(ObjectGraphNode node, long startTime, long count, long totalTime, long totalBeans) {
|
||||
this.node = node;
|
||||
this.startTime = startTime;
|
||||
this.count = count;
|
||||
this.totalTime = totalTime;
|
||||
this.totalBeans = totalBeans;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return node + " count[" + count + "] time[" + totalTime + "] beans[" + totalBeans + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalTime() {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalBeans() {
|
||||
return totalBeans;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.avaje.classpath.scanner.ClassPathScanner;
|
||||
import io.avaje.classpath.scanner.ClassPathScannerFactory;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import org.avaje.classpath.scanner.ClassPathScanner;
|
||||
import org.avaje.classpath.scanner.ClassPathScannerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.config.ContainerConfig;
|
||||
import io.ebean.config.ModuleInfoLoader;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.ServerConfigProvider;
|
||||
import io.ebean.config.TenantMode;
|
||||
@@ -85,11 +86,7 @@ public class DefaultContainer implements SpiContainer {
|
||||
public SpiEbeanServer createServer(ServerConfig serverConfig) {
|
||||
|
||||
synchronized (this) {
|
||||
if (serverConfig.isDefaultServer()) {
|
||||
for (ServerConfigProvider configProvider : ServiceLoader.load(ServerConfigProvider.class)) {
|
||||
configProvider.apply(serverConfig);
|
||||
}
|
||||
}
|
||||
applyConfigServices(serverConfig);
|
||||
|
||||
setNamingConvention(serverConfig);
|
||||
BootupClasses bootupClasses = getBootupClasses(serverConfig);
|
||||
@@ -120,7 +117,6 @@ public class DefaultContainer implements SpiContainer {
|
||||
|
||||
// executor and l2 caching service setup early (used during server construction)
|
||||
SpiBackgroundExecutor executor = createBackgroundExecutor(serverConfig);
|
||||
|
||||
InternalConfiguration c = new InternalConfiguration(online, clusterManager, executor, serverConfig, bootupClasses);
|
||||
|
||||
DefaultServer server = new DefaultServer(c, c.cacheManager());
|
||||
@@ -128,24 +124,45 @@ public class DefaultContainer implements SpiContainer {
|
||||
// generate and run DDL if required
|
||||
// if there are any other tasks requiring action in their plugins, do them as well
|
||||
if (!DbOffline.isGenerateMigration()) {
|
||||
server.executePlugins(online);
|
||||
|
||||
// initialise prior to registering with clusterManager
|
||||
server.initialise();
|
||||
if (online) {
|
||||
if (clusterManager.isClustering()) {
|
||||
// register the server once it has been created
|
||||
clusterManager.registerServer(server);
|
||||
}
|
||||
}
|
||||
// start any services after registering with clusterManager
|
||||
server.start();
|
||||
startServer(online, server);
|
||||
}
|
||||
DbOffline.reset();
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
private void applyConfigServices(ServerConfig config) {
|
||||
if (config.isDefaultServer()) {
|
||||
for (ServerConfigProvider configProvider : ServiceLoader.load(ServerConfigProvider.class)) {
|
||||
configProvider.apply(config);
|
||||
}
|
||||
if (config.isAutoLoadModuleInfo()) {
|
||||
// auto register entity classes (default db)
|
||||
for (ModuleInfoLoader loader : ServiceLoader.load(ModuleInfoLoader.class)) {
|
||||
config.addAll(loader.entityClasses());
|
||||
}
|
||||
}
|
||||
} else if (config.isAutoLoadModuleInfo()) {
|
||||
// auto register entity classes (other named db)
|
||||
for (ModuleInfoLoader loader : ServiceLoader.load(ModuleInfoLoader.class)) {
|
||||
config.addAll(loader.entityClassesFor(config.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startServer(boolean online, DefaultServer server) {
|
||||
server.executePlugins(online);
|
||||
// initialise prior to registering with clusterManager
|
||||
server.initialise();
|
||||
if (online) {
|
||||
if (clusterManager.isClustering()) {
|
||||
clusterManager.registerServer(server);
|
||||
}
|
||||
}
|
||||
// start any services after registering with clusterManager
|
||||
server.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entities, scalarTypes, Listeners etc combining the class registered
|
||||
* ones with the already created instances.
|
||||
|
||||
@@ -4,16 +4,16 @@ import io.ebean.meta.AbstractMetricVisitor;
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaOrmQueryNode;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.MetricData;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanInit;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import io.ebean.meta.ServerMetricsAsJson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -28,8 +28,13 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlan> collectQueryPlans(QueryPlanRequest request) {
|
||||
return server.collectQueryPlans(request);
|
||||
public List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest) {
|
||||
return server.queryPlanInit(initRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request) {
|
||||
return server.queryPlanCollectNow(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,6 +47,16 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
return visitBasic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetricsAsJson collectMetricsAsJson() {
|
||||
return new DumpMetricsJson(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetricData> collectMetricsAsData() {
|
||||
return new DumpMetricsData(server).data();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicMetricVisitor visitBasic() {
|
||||
BasicMetricVisitor basic = new BasicMetricVisitor();
|
||||
@@ -54,18 +69,6 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
server.visitMetrics(new ResetVisitor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaOrmQueryNode> collectNodeStatistics(boolean reset) {
|
||||
|
||||
List<MetaOrmQueryNode> list = new ArrayList<>();
|
||||
for (CObjectGraphNodeStatistics nodeStatistics : server.objectGraphStats.values()) {
|
||||
if (!nodeStatistics.isEmpty()) {
|
||||
list.add(nodeStatistics.get(reset));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor that resets the statistics but doesn't collect them.
|
||||
*/
|
||||
@@ -85,11 +88,6 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOrmQuery(MetaOrmQueryMetric metric) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCount(MetaCountMetric metric) {
|
||||
// ignore
|
||||
|
||||
@@ -38,7 +38,6 @@ import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.bean.PersistenceContext.WithOption;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
@@ -56,6 +55,7 @@ import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanInit;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.plugin.Plugin;
|
||||
@@ -63,9 +63,10 @@ import io.ebean.plugin.Property;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebean.text.csv.CsvReader;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import io.ebean.util.JdbcClose;
|
||||
import io.ebeaninternal.api.ExtraMetrics;
|
||||
import io.ebeaninternal.api.LoadBeanRequest;
|
||||
import io.ebeaninternal.api.LoadManyRequest;
|
||||
import io.ebeaninternal.api.QueryPlanManager;
|
||||
import io.ebeaninternal.api.ScopedTransaction;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.api.SpiDtoQuery;
|
||||
@@ -74,6 +75,8 @@ import io.ebeaninternal.api.SpiJsonContext;
|
||||
import io.ebeaninternal.api.SpiLogManager;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiQuery.Type;
|
||||
import io.ebeaninternal.api.SpiQueryBindCapture;
|
||||
import io.ebeaninternal.api.SpiQueryPlan;
|
||||
import io.ebeaninternal.api.SpiSqlQuery;
|
||||
import io.ebeaninternal.api.SpiSqlUpdate;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
@@ -138,7 +141,6 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
@@ -162,6 +164,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final QueryPlanManager queryPlanManager;
|
||||
|
||||
private final ExtraMetrics extraMetrics;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
/**
|
||||
@@ -240,33 +246,21 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private final boolean updateAllPropertiesInBatch;
|
||||
|
||||
private final boolean collectQueryOrigins;
|
||||
|
||||
private final boolean collectQueryStatsByNode;
|
||||
|
||||
private final long slowQueryMicros;
|
||||
|
||||
private final SlowQueryListener slowQueryListener;
|
||||
|
||||
/**
|
||||
* Cache used to collect statistics based on ObjectGraphNode (used to highlight lazy loading origin points).
|
||||
*/
|
||||
protected final ConcurrentHashMap<ObjectGraphNode, CObjectGraphNodeStatistics> objectGraphStats;
|
||||
|
||||
/**
|
||||
* Create the DefaultServer.
|
||||
*/
|
||||
public DefaultServer(InternalConfiguration config, ServerCacheManager cache) {
|
||||
|
||||
this.logManager = config.getLogManager();
|
||||
this.dtoBeanManager = config.getDtoBeanManager();
|
||||
this.serverConfig = config.getServerConfig();
|
||||
this.objectGraphStats = new ConcurrentHashMap<>();
|
||||
this.metaInfoManager = new DefaultMetaInfoManager(this);
|
||||
this.serverCacheManager = cache;
|
||||
this.databasePlatform = config.getDatabasePlatform();
|
||||
this.backgroundExecutor = config.getBackgroundExecutor();
|
||||
|
||||
this.extraMetrics = config.getExtraMetrics();
|
||||
this.serverName = serverConfig.getName();
|
||||
this.lazyLoadBatchSize = serverConfig.getLazyLoadBatchSize();
|
||||
this.queryBatchSize = serverConfig.getQueryBatchSize();
|
||||
@@ -277,13 +271,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
this.currentTenantProvider = serverConfig.getCurrentTenantProvider();
|
||||
this.slowQueryMicros = config.getSlowQueryMicros();
|
||||
this.slowQueryListener = config.getSlowQueryListener();
|
||||
|
||||
this.beanDescriptorManager = config.getBeanDescriptorManager();
|
||||
beanDescriptorManager.setEbeanServer(this);
|
||||
|
||||
this.updateAllPropertiesInBatch = serverConfig.isUpdateAllPropertiesInBatch();
|
||||
this.collectQueryOrigins = serverConfig.isCollectQueryOrigins();
|
||||
this.collectQueryStatsByNode = serverConfig.isCollectQueryStatsByNode();
|
||||
this.callStackFactory = initCallStackFactory(serverConfig);
|
||||
|
||||
this.persister = config.createPersister(this);
|
||||
@@ -303,6 +293,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
DocStoreIntegration docStoreComponents = config.createDocStoreIntegration(this);
|
||||
this.transactionManager = config.createTransactionManager(docStoreComponents.updateProcessor());
|
||||
this.documentStore = docStoreComponents.documentStore();
|
||||
this.queryPlanManager = config.initQueryPlanManager(transactionManager.getDataSource());
|
||||
this.metaInfoManager = new DefaultMetaInfoManager(this);
|
||||
|
||||
this.serverPlugins = config.getPlugins();
|
||||
this.ddlGenerator = new DdlGenerator(this, serverConfig);
|
||||
@@ -352,11 +344,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return logManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollectQueryOrigins() {
|
||||
return collectQueryOrigins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdateAllPropertiesInBatch() {
|
||||
return updateAllPropertiesInBatch;
|
||||
@@ -1262,16 +1249,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
public <T> Set<T> findSet(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest request = createQueryRequest(Type.SET, query, t);
|
||||
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
return (Set<T>) result;
|
||||
}
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findSet();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
@@ -1282,16 +1266,18 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
public <K, T> Map<K, T> findMap(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest request = createQueryRequest(Type.MAP, query, t);
|
||||
|
||||
request.resetBeanCacheAutoMode(false);
|
||||
if ((t == null || !t.isSkipCache()) && request.getFromBeanCache()) {
|
||||
// hit bean cache and got all results from cache
|
||||
return request.getBeanCacheHitsAsMap();
|
||||
}
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
return (Map<K, T>) result;
|
||||
}
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findMap();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
@@ -2357,21 +2343,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return jsonContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectQueryStats(ObjectGraphNode node, long loadedBeanCount, long timeMicros) {
|
||||
|
||||
if (collectQueryStatsByNode) {
|
||||
CObjectGraphNodeStatistics nodeStatistics = objectGraphStats.get(node);
|
||||
if (nodeStatistics == null) {
|
||||
// race condition here but I actually don't care too much if we miss a
|
||||
// few early statistics - especially when the server is warming up etc
|
||||
nodeStatistics = new CObjectGraphNodeStatistics(node);
|
||||
objectGraphStats.put(node, nodeStatistics);
|
||||
}
|
||||
nodeStatistics.add(loadedBeanCount, timeMicros);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void slowQueryCheck(long timeMicros, int rowCount, SpiQuery<?> query) {
|
||||
if (timeMicros > slowQueryMicros && slowQueryListener != null) {
|
||||
@@ -2418,7 +2389,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a set of properties if saving the bean will violate the unique constraints (defined by given properties).
|
||||
*/
|
||||
@@ -2463,21 +2433,20 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
relationalQueryEngine.visitMetrics(visitor);
|
||||
persister.visitMetrics(visitor);
|
||||
}
|
||||
extraMetrics.visitMetrics(visitor);
|
||||
visitor.visitEnd();
|
||||
}
|
||||
|
||||
public List<MetaQueryPlan> collectQueryPlans(QueryPlanRequest request) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = getDataSource().getConnection();
|
||||
request.setConnection(connection);
|
||||
beanDescriptorManager.collectQueryPlans(request);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@Override
|
||||
public SpiQueryBindCapture createQueryBindCapture(SpiQueryPlan plan) {
|
||||
return queryPlanManager.createBindCapture(plan);
|
||||
}
|
||||
|
||||
} finally {
|
||||
JdbcClose.close(connection);
|
||||
}
|
||||
return request.getPlans();
|
||||
List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest) {
|
||||
return beanDescriptorManager.queryPlanInit(initRequest);
|
||||
}
|
||||
|
||||
List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request) {
|
||||
return queryPlanManager.collect(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,11 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
this(null, sql, new BindParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiSqlUpdate copy() {
|
||||
return new DefaultSqlUpdate(server, origSql, new BindParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
addPos = 0;
|
||||
|
||||
@@ -31,8 +31,6 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
|
||||
private DataReader dataReader;
|
||||
|
||||
private int beanCount;
|
||||
|
||||
DtoQueryRequest(SpiEbeanServer server, DtoQueryEngine engine, SpiDtoQuery<T> query) {
|
||||
super(server, query, null);
|
||||
this.queryEngine = engine;
|
||||
@@ -85,7 +83,7 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
protected void requestComplete() {
|
||||
if (plan != null) {
|
||||
long exeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
plan.collect(exeMicros, beanCount);
|
||||
plan.collect(exeMicros);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +101,6 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T readNextBean() throws SQLException {
|
||||
beanCount++;
|
||||
dataReader.resetColumnPosition();
|
||||
return (T)plan.readRow(dataReader);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
@@ -93,23 +91,14 @@ class DumpMetrics {
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = serverMetrics.getOrmQueryMetrics();
|
||||
if (!ormQueryMetrics.isEmpty()) {
|
||||
out("\n-- ORM queries --");
|
||||
ormQueryMetrics.sort(sortBy);
|
||||
for (MetaOrmQueryMetric metric : ormQueryMetrics) {
|
||||
List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
|
||||
if (!queryMetrics.isEmpty()) {
|
||||
out("\n-- Queries --");
|
||||
queryMetrics.sort(sortBy);
|
||||
for (MetaQueryMetric metric : queryMetrics) {
|
||||
logQuery(metric);
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaQueryMetric> dtoQueryMetrics = serverMetrics.getDtoQueryMetrics();
|
||||
if (!dtoQueryMetrics.isEmpty()) {
|
||||
out("\n-- DTO queries --");
|
||||
dtoQueryMetrics.sort(sortBy);
|
||||
for (MetaQueryMetric metric : dtoQueryMetrics) {
|
||||
logDtoQuery(metric);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void logCount(MetaCountMetric metric) {
|
||||
@@ -124,47 +113,34 @@ class DumpMetrics {
|
||||
System.out.println(sb);
|
||||
}
|
||||
|
||||
private void logQuery(MetaOrmQueryMetric metric) {
|
||||
private void logQuery(MetaQueryMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
appendQueryName(metric, sb);
|
||||
appendCounters(metric, sb);
|
||||
if (dumpHash) {
|
||||
sb.append("\n hash:").append(metric.getSqlHash());
|
||||
sb.append("\n hash:").append(metric.getHash());
|
||||
}
|
||||
appendProfileAndSql(metric, sb);
|
||||
out(sb.toString());
|
||||
}
|
||||
|
||||
|
||||
private void logDtoQuery(MetaQueryMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
appendQueryName(metric, sb);
|
||||
appendCounters(metric, sb);
|
||||
appendProfileAndSql(metric, sb);
|
||||
out(sb.toString());
|
||||
}
|
||||
|
||||
private void appendQueryName(MetaQueryMetric metric, StringBuilder sb) {
|
||||
sb.append("query:").append(padName(metric.getName())).append(" ");
|
||||
}
|
||||
|
||||
private void appendProfileAndSql(MetaQueryMetric metric, StringBuilder sb) {
|
||||
ProfileLocation profileLocation = metric.getProfileLocation();
|
||||
if (dumpLoc && profileLocation != null) {
|
||||
sb.append("\n loc:").append(profileLocation.shortDescription());
|
||||
String location = metric.getLocation();
|
||||
if (dumpLoc && location != null) {
|
||||
sb.append("\n loc:").append(location);
|
||||
}
|
||||
|
||||
if (dumpSql) {
|
||||
sb.append(" \n\n sql:").append(metric.getSql()).append("\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void log(MetaTimedMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(padNameTimed(metric.getName())).append(" ");
|
||||
appendCounters(metric, sb);
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaMetric;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.MetricData;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Dump the metrics into a list of MetricData.
|
||||
*/
|
||||
class DumpMetricsData {
|
||||
|
||||
private final Database database;
|
||||
|
||||
private final List<MetricData> list = new ArrayList<>();
|
||||
|
||||
DumpMetricsData(Database database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
List<MetricData> data() {
|
||||
collect(database.getMetaInfoManager().collectMetrics());
|
||||
return list;
|
||||
}
|
||||
|
||||
private void collect(ServerMetrics serverMetrics) {
|
||||
|
||||
final List<MetaTimedMetric> timedMetrics = serverMetrics.getTimedMetrics();
|
||||
final List<MetaCountMetric> countMetrics = serverMetrics.getCountMetrics();
|
||||
final List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
|
||||
|
||||
for (MetaTimedMetric metric : timedMetrics) {
|
||||
add(metric);
|
||||
}
|
||||
for (MetaCountMetric metric : countMetrics) {
|
||||
addCount(metric);
|
||||
}
|
||||
for (MetaQueryMetric metric : queryMetrics) {
|
||||
addQuery(metric);
|
||||
}
|
||||
}
|
||||
|
||||
private MetricData create(MetaMetric metric) {
|
||||
MetricData data = new MetricData(metric.getName(), metric.getMetricType().name());
|
||||
list.add(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private void add(MetaTimedMetric metric) {
|
||||
final MetricData data = create(metric);
|
||||
appendCounters(data, metric);
|
||||
data.setLoc(metric.getLocation());
|
||||
}
|
||||
|
||||
private void addCount(MetaCountMetric metric) {
|
||||
final MetricData data = create(metric);
|
||||
data.setCount(metric.getCount());
|
||||
}
|
||||
|
||||
private void addQuery(MetaQueryMetric metric) {
|
||||
final MetricData data = create(metric);
|
||||
appendCounters(data, metric);
|
||||
appendLocationAndSql(data, metric);
|
||||
data.setHash(metric.getHash());
|
||||
}
|
||||
|
||||
private void appendLocationAndSql(MetricData data, MetaQueryMetric metric) {
|
||||
data.setLoc(metric.getLocation());
|
||||
data.setSql(metric.getSql());
|
||||
}
|
||||
|
||||
private void appendCounters(MetricData data, MetaTimedMetric timedMetric) {
|
||||
data.setCount(timedMetric.getCount());
|
||||
data.setTotal(timedMetric.getTotal());
|
||||
data.setMean(timedMetric.getMean());
|
||||
data.setMax(timedMetric.getMax());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.meta.MetaCountMetric;
|
||||
import io.ebean.meta.MetaMetric;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import io.ebean.meta.ServerMetricsAsJson;
|
||||
import io.ebean.meta.SortMetric;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
class DumpMetricsJson implements ServerMetricsAsJson {
|
||||
|
||||
private final Database database;
|
||||
|
||||
private Appendable writer;
|
||||
|
||||
/**
|
||||
* By default include sql and location attributes for the initial collection only.
|
||||
*/
|
||||
private int includeExtraAttributes = 1;
|
||||
|
||||
private boolean withHeader = true;
|
||||
private boolean withHash = true;
|
||||
private String newLine = "\n";
|
||||
|
||||
private Comparator<MetaTimedMetric> sortBy = SortMetric.NAME;
|
||||
|
||||
private int listCounter;
|
||||
private int objKeyCounter;
|
||||
|
||||
DumpMetricsJson(Database database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetricsAsJson withHeader(boolean withHeader) {
|
||||
this.withHeader = withHeader;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetricsAsJson withExtraAttributes(boolean extraAttributes) {
|
||||
this.includeExtraAttributes = extraAttributes ? 2 : 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetricsAsJson withHash(boolean withHash) {
|
||||
this.withHash = withHash;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetricsAsJson withSort(Comparator<MetaTimedMetric> sortBy) {
|
||||
this.sortBy = sortBy;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetricsAsJson withNewLine(boolean withNewLine) {
|
||||
this.newLine = withNewLine ? "\n" : "";
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String json() {
|
||||
writer = new StringWriter();
|
||||
collect(database.getMetaInfoManager().collectMetrics());
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Appendable buffer) {
|
||||
writer = buffer;
|
||||
collect(database.getMetaInfoManager().collectMetrics());
|
||||
}
|
||||
|
||||
private void collect(ServerMetrics serverMetrics) {
|
||||
try {
|
||||
start();
|
||||
for (MetaTimedMetric metric : serverMetrics.getTimedMetrics()) {
|
||||
logTimed(metric);
|
||||
}
|
||||
|
||||
List<MetaCountMetric> countMetrics = serverMetrics.getCountMetrics();
|
||||
if (!countMetrics.isEmpty()) {
|
||||
if (sortBy != null) {
|
||||
countMetrics.sort(SortMetric.COUNT_NAME);
|
||||
}
|
||||
for (MetaCountMetric metric : countMetrics) {
|
||||
logCount(metric);
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
|
||||
if (!queryMetrics.isEmpty()) {
|
||||
if (sortBy != null) {
|
||||
queryMetrics.sort(sortBy);
|
||||
}
|
||||
for (MetaQueryMetric metric : queryMetrics) {
|
||||
logQuery(metric);
|
||||
}
|
||||
}
|
||||
end();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error writing metrics as JSON", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void start() throws IOException {
|
||||
if (withHeader) {
|
||||
objStart();
|
||||
key("db");
|
||||
val(database.getName());
|
||||
key("metrics");
|
||||
listStart();
|
||||
}
|
||||
}
|
||||
|
||||
private void end() throws IOException {
|
||||
if (withHeader) {
|
||||
listEnd();
|
||||
objEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void objStart() throws IOException {
|
||||
objKeyCounter = 0;
|
||||
writer.append("{");
|
||||
}
|
||||
|
||||
private void objEnd() throws IOException {
|
||||
writer.append("}");
|
||||
}
|
||||
|
||||
private void listStart() throws IOException {
|
||||
listCounter = 0;
|
||||
writer.append("[");
|
||||
writer.append(newLine);
|
||||
}
|
||||
|
||||
private void listEnd() throws IOException {
|
||||
writer.append("]");
|
||||
}
|
||||
|
||||
private void key(String key) throws IOException {
|
||||
if (objKeyCounter++ > 0) {
|
||||
writer.append(", ");
|
||||
}
|
||||
writer.append("\"").append(key).append("\":");
|
||||
}
|
||||
|
||||
private void val(long count) throws IOException {
|
||||
writer.append(Long.toString(count));
|
||||
}
|
||||
|
||||
private void val(String val) throws IOException {
|
||||
writer.append("\"").append(val).append("\"");
|
||||
}
|
||||
|
||||
private void metricStart(MetaMetric metric) throws IOException {
|
||||
if (listCounter++ > 0) {
|
||||
writer.append(",").append(newLine);
|
||||
}
|
||||
objStart();
|
||||
key("name");
|
||||
val(metric.getName());
|
||||
}
|
||||
|
||||
private void metricEnd() throws IOException {
|
||||
objEnd();
|
||||
}
|
||||
|
||||
private void logCount(MetaCountMetric metric) throws IOException {
|
||||
metricStart(metric);
|
||||
key("count");
|
||||
val(metric.getCount());
|
||||
metricEnd();
|
||||
}
|
||||
|
||||
private void logTimed(MetaTimedMetric metric) throws IOException {
|
||||
metricStart(metric);
|
||||
appendTiming(metric);
|
||||
if (isIncludeDetail(metric)) {
|
||||
appendExtra("loc", metric.getLocation());
|
||||
}
|
||||
metricEnd();
|
||||
}
|
||||
|
||||
private void logQuery(MetaQueryMetric metric) throws IOException {
|
||||
metricStart(metric);
|
||||
appendTiming(metric);
|
||||
if (withHash) {
|
||||
appendExtra("hash", metric.getHash());
|
||||
}
|
||||
if (isIncludeDetail(metric)) {
|
||||
appendExtra("loc", metric.getLocation());
|
||||
appendExtra("sql", metric.getSql());
|
||||
}
|
||||
metricEnd();
|
||||
}
|
||||
|
||||
private boolean isIncludeDetail(MetaTimedMetric metric) {
|
||||
return includeExtraAttributes == 2 || includeExtraAttributes == 1 && metric.initialCollection();
|
||||
}
|
||||
|
||||
private void appendExtra(String key, String val) throws IOException {
|
||||
if (val != null) {
|
||||
key(key);
|
||||
val(val);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendTiming(MetaTimedMetric timedMetric) throws IOException {
|
||||
key("count");
|
||||
val(timedMetric.getCount());
|
||||
key("total");
|
||||
val(timedMetric.getTotal());
|
||||
key("mean");
|
||||
val(timedMetric.getMean());
|
||||
key("max");
|
||||
val(timedMetric.getMax());
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.avaje.classpath.scanner.ClassPathScanner;
|
||||
import io.avaje.classpath.scanner.Resource;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebeaninternal.server.dto.DtoNamedQueries;
|
||||
import io.ebeaninternal.xmlmapping.XmlMappingReader;
|
||||
import io.ebeaninternal.xmlmapping.model.XmDto;
|
||||
import io.ebeaninternal.xmlmapping.model.XmEbean;
|
||||
import io.ebeaninternal.xmlmapping.model.XmRawSql;
|
||||
import org.avaje.classpath.scanner.ClassPathScanner;
|
||||
import org.avaje.classpath.scanner.Resource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.plugin.Plugin;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebeaninternal.api.ExtraMetrics;
|
||||
import io.ebeaninternal.api.QueryPlanManager;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiJsonContext;
|
||||
@@ -64,9 +66,15 @@ import io.ebeaninternal.server.persist.DefaultPersister;
|
||||
import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.persist.platform.PostgresMultiValueBind;
|
||||
import io.ebeaninternal.server.query.CQueryEngine;
|
||||
import io.ebeaninternal.server.query.CQueryPlanManager;
|
||||
import io.ebeaninternal.server.query.DefaultOrmQueryEngine;
|
||||
import io.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import io.ebeaninternal.server.query.DtoQueryEngine;
|
||||
import io.ebeaninternal.server.query.QueryPlanLogger;
|
||||
import io.ebeaninternal.server.query.QueryPlanLoggerExplain;
|
||||
import io.ebeaninternal.server.query.QueryPlanLoggerOracle;
|
||||
import io.ebeaninternal.server.query.QueryPlanLoggerPostgres;
|
||||
import io.ebeaninternal.server.query.QueryPlanLoggerSqlServer;
|
||||
import io.ebeaninternal.server.readaudit.DefaultReadAuditLogger;
|
||||
import io.ebeaninternal.server.readaudit.DefaultReadAuditPrepare;
|
||||
import io.ebeaninternal.server.text.json.DJsonContext;
|
||||
@@ -164,8 +172,10 @@ public class InternalConfiguration {
|
||||
|
||||
private final SpiLogManager logManager;
|
||||
|
||||
private final ExtraMetrics extraMetrics = new ExtraMetrics();
|
||||
|
||||
InternalConfiguration(boolean online, ClusterManager clusterManager, SpiBackgroundExecutor backgroundExecutor,
|
||||
ServerConfig serverConfig, BootupClasses bootupClasses) {
|
||||
ServerConfig serverConfig, BootupClasses bootupClasses) {
|
||||
|
||||
this.online = online;
|
||||
this.serverConfig = serverConfig;
|
||||
@@ -242,6 +252,10 @@ public class InternalConfiguration {
|
||||
return clockService;
|
||||
}
|
||||
|
||||
public ExtraMetrics getExtraMetrics() {
|
||||
return extraMetrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a SpiServerPlugin and if so 'collect' it to give the complete list
|
||||
* later on the DefaultServer for late call to configure().
|
||||
@@ -433,8 +447,8 @@ public class InternalConfiguration {
|
||||
|
||||
TransactionManagerOptions options =
|
||||
new TransactionManagerOptions(notifyL2CacheInForeground, serverConfig, scopeManager, clusterManager, backgroundExecutor,
|
||||
indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler(), logManager,
|
||||
tableModState, cacheNotify, clockService);
|
||||
indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler(), logManager,
|
||||
tableModState, cacheNotify, clockService);
|
||||
|
||||
if (serverConfig.isExplicitTransactionBeginMode()) {
|
||||
return new ExplicitTransactionManager(options);
|
||||
@@ -527,7 +541,7 @@ public class InternalConfiguration {
|
||||
}
|
||||
|
||||
private boolean isMySql(Platform platform) {
|
||||
return platform.base() == Platform.MYSQL;
|
||||
return platform.base() == Platform.MYSQL;
|
||||
}
|
||||
|
||||
public DataTimeZone getDataTimeZone() {
|
||||
@@ -636,4 +650,28 @@ public class InternalConfiguration {
|
||||
|
||||
return new DefaultServerCacheManager(builder);
|
||||
}
|
||||
|
||||
public QueryPlanManager initQueryPlanManager(DataSource dataSource) {
|
||||
if (!serverConfig.isCollectQueryPlans()) {
|
||||
return QueryPlanManager.NOOP;
|
||||
}
|
||||
long threshold = serverConfig.getCollectQueryPlanThresholdMicros();
|
||||
return new CQueryPlanManager(dataSource, threshold, queryPlanLogger(databasePlatform.getPlatform()), extraMetrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logger to log query plans for the given platform.
|
||||
*/
|
||||
QueryPlanLogger queryPlanLogger(Platform platform) {
|
||||
switch (platform.base()) {
|
||||
case POSTGRES:
|
||||
return new QueryPlanLoggerPostgres();
|
||||
case SQLSERVER:
|
||||
return new QueryPlanLoggerSqlServer();
|
||||
case ORACLE:
|
||||
return new QueryPlanLoggerOracle();
|
||||
default:
|
||||
return new QueryPlanLoggerExplain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.cache.QueryCacheEntry;
|
||||
import io.ebean.common.BeanList;
|
||||
import io.ebean.common.BeanMap;
|
||||
import io.ebean.common.CopyOnFirstWriteList;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanQueryAdapter;
|
||||
@@ -31,6 +32,7 @@ import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.DeployParser;
|
||||
import io.ebeaninternal.server.deploy.DeployPropertyParserMap;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.loadcontext.DLoadContext;
|
||||
import io.ebeaninternal.server.query.CQueryPlan;
|
||||
import io.ebeaninternal.server.query.CancelableQuery;
|
||||
@@ -586,19 +588,36 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
public void mergeCacheHits(BeanCollection<T> result) {
|
||||
|
||||
if (cacheBeans != null && !cacheBeans.isEmpty()) {
|
||||
for (T hit : cacheBeans) {
|
||||
result.internalAdd(hit);
|
||||
if (query.getType() == Type.MAP) {
|
||||
mergeCacheHitsToMap(result);
|
||||
} else {
|
||||
mergeCacheHitsToList(result);
|
||||
}
|
||||
// resort in memory here after merging the cache hits with the DB hits
|
||||
if (result instanceof BeanList) {
|
||||
OrderBy<T> orderBy = query.getOrderBy();
|
||||
if (orderBy != null) {
|
||||
beanDescriptor.sort(((BeanList<T>)result).getActualList(), orderBy.toStringFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeCacheHitsToList(BeanCollection<T> result) {
|
||||
for (T hit : cacheBeans) {
|
||||
result.internalAdd(hit);
|
||||
}
|
||||
if (result instanceof BeanList) {
|
||||
OrderBy<T> orderBy = query.getOrderBy();
|
||||
if (orderBy != null) {
|
||||
// in memory sort after merging the cache hits with the DB hits
|
||||
beanDescriptor.sort(((BeanList<T>) result).getActualList(), orderBy.toStringFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes"})
|
||||
private void mergeCacheHitsToMap(BeanCollection<T> result) {
|
||||
BeanMap map = (BeanMap)result;
|
||||
ElPropertyValue property = mapProperty();
|
||||
for (T bean : cacheBeans) {
|
||||
map.internalPut(property.pathGet(bean), bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getBeanCacheHits() {
|
||||
OrderBy<T> orderBy = query.getOrderBy();
|
||||
@@ -608,6 +627,33 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
return cacheBeans;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K> Map<K, T> getBeanCacheHitsAsMap() {
|
||||
OrderBy<T> orderBy = query.getOrderBy();
|
||||
if (orderBy != null) {
|
||||
beanDescriptor.sort(cacheBeans, orderBy.toStringFormat());
|
||||
}
|
||||
return cacheBeansToMap();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K> Map<K, T> cacheBeansToMap() {
|
||||
ElPropertyValue property = mapProperty();
|
||||
Map<K,T> map = new LinkedHashMap<>();
|
||||
for (T bean : cacheBeans) {
|
||||
map.put((K)property.pathGet(bean), bean);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private ElPropertyValue mapProperty() {
|
||||
ElPropertyValue property = beanDescriptor.getElGetValue(query.getMapKey());
|
||||
if (property == null) {
|
||||
throw new IllegalStateException("Unknown map key property "+query.getMapKey());
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFromBeanCache() {
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public class PersistDeferredRelationship {
|
||||
public void execute(SpiTransaction transaction) {
|
||||
|
||||
String sql = beanDescriptor.getUpdateImportedIdSql(importedId);
|
||||
SqlUpdate sqlUpdate = ebeanServer.createSqlUpdate(sql);
|
||||
SqlUpdate sqlUpdate = ebeanServer.sqlUpdate(sql);
|
||||
|
||||
// bind the set clause for the importedId
|
||||
int pos = importedId.bind(1, sqlUpdate, assocBean);
|
||||
|
||||
@@ -57,6 +57,15 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTimingBatch(long startNanos, int size) {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
public void addTimingNoBatch(long startNanos) {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Effectively set start nanos if we are collecting metrics on a label.
|
||||
*/
|
||||
@@ -66,6 +75,11 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlushQueue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a the request or queue/batch it for later execution.
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ import io.ebeaninternal.server.persist.BatchedSqlException;
|
||||
import io.ebeaninternal.server.persist.DeleteMode;
|
||||
import io.ebeaninternal.server.persist.Flags;
|
||||
import io.ebeaninternal.server.persist.PersistExecute;
|
||||
import io.ebeaninternal.server.persist.SaveManyBeans;
|
||||
import io.ebeaninternal.server.persist.SaveMany;
|
||||
import io.ebeaninternal.server.transaction.BeanPersistIdMap;
|
||||
import io.ebeanservice.docstore.api.DocStoreUpdate;
|
||||
import io.ebeanservice.docstore.api.DocStoreUpdateContext;
|
||||
@@ -169,10 +169,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
*/
|
||||
private boolean getterCallback;
|
||||
|
||||
/**
|
||||
* postUpdate notifications. Used to combine bean and element update updates into single postUpdate event.
|
||||
*/
|
||||
private int pendingPostUpdateNotify;
|
||||
private boolean pendingPostUpdateNotify;
|
||||
|
||||
/**
|
||||
* Set to true when post execute has occurred (so includes batch flush).
|
||||
@@ -187,7 +184,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
/**
|
||||
* Many to many intersection table changes that are held for later batch processing.
|
||||
*/
|
||||
private List<SaveManyBeans> saveManyIntersections;
|
||||
private List<SaveMany> saveMany;
|
||||
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||
PersistExecute persistExecute, PersistRequest.Type type, int flags) {
|
||||
@@ -232,6 +229,16 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
initGeneratedProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTimingBatch(long startNanos, int batch) {
|
||||
beanDescriptor.metricPersistBatch(type, startNanos, batch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTimingNoBatch(long startNanos) {
|
||||
beanDescriptor.metricPersistNoBatch(type, startNanos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to profile as batched bean insert, update or delete.
|
||||
*/
|
||||
@@ -889,12 +896,8 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
|
||||
private void postUpdateNotify() {
|
||||
if (pendingPostUpdateNotify > 0) {
|
||||
// invoke the delayed postUpdate notification (combined with element collection update)
|
||||
if (pendingPostUpdateNotify) {
|
||||
controller.postUpdate(this);
|
||||
} else {
|
||||
// batched update with no element collection, send postUpdate notification once it executes
|
||||
pendingPostUpdateNotify = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,6 +920,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
*/
|
||||
@Override
|
||||
public void postExecute() {
|
||||
saveQueuedMany();
|
||||
postExecute = true;
|
||||
if (controller != null) {
|
||||
controllerPost();
|
||||
@@ -944,12 +948,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
if (isLogSummary()) {
|
||||
logSummary();
|
||||
}
|
||||
saveQueuedManyIntersection();
|
||||
}
|
||||
|
||||
private void saveQueuedManyIntersection() {
|
||||
if (saveManyIntersections != null) {
|
||||
saveManyIntersections.forEach(SaveManyBeans::saveIntersectionBatch);
|
||||
private void saveQueuedMany() {
|
||||
if (saveMany != null) {
|
||||
saveMany.forEach(SaveMany::saveBatch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,19 +963,14 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
if (controller != null && !dirty) {
|
||||
// fire preUpdate notification when only element collection updated
|
||||
controller.preUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine with the beans postUpdate event notification.
|
||||
*/
|
||||
public boolean postElementCollectionUpdate() {
|
||||
if (controller != null) {
|
||||
pendingPostUpdateNotify += 2;
|
||||
pendingPostUpdateNotify = true;
|
||||
}
|
||||
if (!dirty) {
|
||||
setNotifyCache();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNotifyCache() {
|
||||
return notifyCache;
|
||||
}
|
||||
|
||||
@@ -982,13 +980,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
controller.postInsert(this);
|
||||
break;
|
||||
case UPDATE:
|
||||
if (pendingPostUpdateNotify == -1) {
|
||||
// notify now - batched bean update with no element collection
|
||||
controller.postUpdate(this);
|
||||
} else {
|
||||
// delay notify to combine with element collection update
|
||||
pendingPostUpdateNotify++;
|
||||
}
|
||||
controller.postUpdate(this);
|
||||
break;
|
||||
case DELETE_SOFT:
|
||||
controller.postSoftDelete(this);
|
||||
@@ -1105,7 +1097,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
updatedManysOnly = true;
|
||||
setNotifyCache();
|
||||
addPostCommitListeners();
|
||||
saveQueuedManyIntersection();
|
||||
saveQueuedMany();
|
||||
}
|
||||
notifyCacheOnComplete();
|
||||
postUpdateNotify();
|
||||
@@ -1444,20 +1436,20 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the intersection table updates should be queued and batched.
|
||||
* Return true if the intersection table updates or element collection updates should be queued.
|
||||
*/
|
||||
public boolean isQueueManyIntersection() {
|
||||
public boolean isQueueSaveMany() {
|
||||
return !postExecute;
|
||||
}
|
||||
|
||||
/**
|
||||
* The intersection table updates to the batch executed later on postExecute.
|
||||
* The intersection table updates or element collection to the batch executed later on postExecute.
|
||||
*/
|
||||
public void addManyIntersection(SaveManyBeans saveManyIntersection) {
|
||||
if (this.saveManyIntersections == null) {
|
||||
this.saveManyIntersections = new ArrayList<>();
|
||||
public void addSaveMany(SaveMany saveManyRequest) {
|
||||
if (this.saveMany == null) {
|
||||
this.saveMany = new ArrayList<>();
|
||||
}
|
||||
this.saveManyIntersections.add(saveManyIntersection);
|
||||
this.saveMany.add(saveManyRequest);
|
||||
}
|
||||
|
||||
public boolean isForcedUpdate() {
|
||||
@@ -1471,7 +1463,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
saveRecurse = true;
|
||||
}
|
||||
|
||||
public void setGeneratedId() {
|
||||
private void setGeneratedId() {
|
||||
beanDescriptor.setGeneratedId(entityBean, transaction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public final class PersistRequestCallableSql extends PersistRequest {
|
||||
@Override
|
||||
public void postExecute() {
|
||||
if (startNanos > 0) {
|
||||
persistExecute.collectSqlCall(label, startNanos, rowCount);
|
||||
persistExecute.collectSqlCall(label, startNanos);
|
||||
}
|
||||
if (transaction.isLogSummary()) {
|
||||
String m = "CallableSql label[" + callableSql.getLabel() + "]" + " rows[" + rowCount + "]" + " bind[" + bindLog + "]";
|
||||
|
||||
@@ -87,7 +87,7 @@ public final class PersistRequestOrmUpdate extends PersistRequest {
|
||||
@Override
|
||||
public void postExecute() {
|
||||
if (startNanos > 0) {
|
||||
persistExecute.collectOrmUpdate(label, startNanos, rowCount);
|
||||
persistExecute.collectOrmUpdate(label, startNanos);
|
||||
}
|
||||
OrmUpdateType ormUpdateType = ormUpdate.getOrmUpdateType();
|
||||
String tableName = ormUpdate.getBaseTable();
|
||||
|
||||
@@ -32,6 +32,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
private final boolean forceNoBatch;
|
||||
|
||||
private boolean batchThisRequest;
|
||||
private boolean flushQueue;
|
||||
|
||||
public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate,
|
||||
SpiTransaction t, PersistExecute persistExecute, boolean forceNoBatch) {
|
||||
@@ -50,7 +51,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
|
||||
@Override
|
||||
public void profile(long offset, int flushCount) {
|
||||
profileBase(EVT_UPDATESQL, offset, (short)0, flushCount);
|
||||
profileBase(EVT_UPDATESQL, offset, (short) 0, flushCount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,9 +78,15 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
if (control == null) {
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
}
|
||||
flushQueue = true;
|
||||
control.addToFlushQueue(this, early);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlushQueue() {
|
||||
return flushQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
return persistExecute.executeSqlUpdate(this);
|
||||
@@ -158,7 +165,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
@Override
|
||||
public void postExecute() {
|
||||
if (startNanos > 0) {
|
||||
persistExecute.collectSqlUpdate(label, startNanos, rowCount);
|
||||
persistExecute.collectSqlUpdate(label, startNanos);
|
||||
}
|
||||
if (transaction.isLogSql() && !batchThisRequest) {
|
||||
transaction.logSql(Str.add(TrimLogSql.trim(updateSql.getGeneratedSql()), "; -- bind(", bindLog, ") rows(", String.valueOf(rowCount), ")"));
|
||||
|
||||
@@ -104,8 +104,18 @@ public interface Persister {
|
||||
void executeOrQueue(SpiSqlUpdate update, SpiTransaction t, boolean queue);
|
||||
|
||||
/**
|
||||
* Add the statement to JDBC batch for later execution via executeBatch.
|
||||
* Queue the SqlUpdate for early execution (with JDBC batch).
|
||||
*/
|
||||
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t);
|
||||
|
||||
/**
|
||||
* Queue the SqlUpdate for late execution (with JDBC batch).
|
||||
*/
|
||||
void addToFlushQueueLast(SpiSqlUpdate update, SpiTransaction t);
|
||||
|
||||
/**
|
||||
* Add the statement to JDBC batch for later execution via executeBatch.
|
||||
*/
|
||||
void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
|
||||
|
||||
/**
|
||||
|
||||
@@ -60,7 +60,7 @@ public interface RelationalQueryEngine {
|
||||
/**
|
||||
* Collect SQL query execution statistics.
|
||||
*/
|
||||
void collect(String label, long exeMicros, int rows);
|
||||
void collect(String label, long exeMicros);
|
||||
|
||||
/**
|
||||
* Visit the metrics.
|
||||
|
||||
@@ -51,7 +51,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
String label = query.getLabel();
|
||||
if (label != null) {
|
||||
long exeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
queryEngine.collect(label, exeMicros, rows);
|
||||
queryEngine.collect(label, exeMicros);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,11 @@ public interface SpiOrmQueryRequest<T> extends BeanQueryRequest<T>, DocQueryRequ
|
||||
*/
|
||||
List<T> getBeanCacheHits();
|
||||
|
||||
/**
|
||||
* Return the bean cache hits for findMap (when all hits / no misses).
|
||||
*/
|
||||
<K> Map<K,T> getBeanCacheHitsAsMap();
|
||||
|
||||
/**
|
||||
* Reset Bean cache mode AUTO - require explicit setting for bean cache use with findList().
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.core.bootup;
|
||||
|
||||
import io.avaje.classpath.scanner.ClassPathScanner;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebeaninternal.server.core.ClassPathScanners;
|
||||
import org.avaje.classpath.scanner.ClassPathScanner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.core.bootup;
|
||||
|
||||
import io.avaje.classpath.scanner.ClassFilter;
|
||||
import io.ebean.annotation.DocStore;
|
||||
import io.ebean.config.IdGenerator;
|
||||
import io.ebean.config.ScalarTypeConverter;
|
||||
@@ -18,7 +19,6 @@ import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import org.avaje.classpath.scanner.ClassFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -129,7 +129,7 @@ public class BootupClasses implements ClassFilter {
|
||||
|
||||
/**
|
||||
* Adds the list <code>toAdd</code> to <code>instances</code> and removes any pending
|
||||
* candiate, to prevent duplicate instantiiation.
|
||||
* candidate, to prevent duplicate instantiation.
|
||||
*/
|
||||
private <T> void add(List<T> toAdd, List<T> instances, List<Class<? extends T>> candidates) {
|
||||
if (toAdd != null) {
|
||||
@@ -433,9 +433,7 @@ public class BootupClasses implements ClassFilter {
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
// single instances
|
||||
// TODO: What should happen, if there is already an other
|
||||
// changeLogListener assigned? (Last wins? / Exception?)
|
||||
// single instances, last assigned wins
|
||||
if (ChangeLogListener.class.isAssignableFrom(cls)) {
|
||||
changeLogListenerClass = (Class<? extends ChangeLogListener>) cls;
|
||||
interesting = true;
|
||||
|
||||
@@ -27,8 +27,9 @@ import io.ebean.event.changelog.ChangeType;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.event.readaudit.ReadEvent;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.meta.QueryPlanInit;
|
||||
import io.ebean.plugin.BeanDocType;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.plugin.ExpressionPath;
|
||||
@@ -143,6 +144,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
private boolean batchEscalateOnCascadeInsert;
|
||||
private boolean batchEscalateOnCascadeDelete;
|
||||
|
||||
private final BeanIudMetrics iudMetrics;
|
||||
|
||||
public enum EntityType {
|
||||
ORM, EMBEDDED, VIEW, SQL, DOC
|
||||
}
|
||||
@@ -375,6 +378,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
private final BeanProperty[] propertiesGenUpdate;
|
||||
private final List<BeanProperty[]> propertiesUnique = new ArrayList<>();
|
||||
|
||||
private BeanNaturalKey beanNaturalKey;
|
||||
|
||||
/**
|
||||
* The bean class name or the table name for MapBeans.
|
||||
*/
|
||||
@@ -439,7 +444,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
this.beanType = deploy.getBeanType();
|
||||
this.rootBeanType = PersistenceContextUtil.root(beanType);
|
||||
this.prototypeEntityBean = createPrototypeEntityBean(beanType);
|
||||
|
||||
this.iudMetrics = new BeanIudMetrics(name);
|
||||
this.namedQuery = deploy.getNamedQuery();
|
||||
this.namedRawSql = deploy.getNamedRawSql();
|
||||
this.inheritInfo = deploy.getInheritInfo();
|
||||
@@ -478,7 +483,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
this.dbComment = deploy.getDbComment();
|
||||
this.partitionMeta = deploy.getPartitionMeta();
|
||||
this.storageEngine = deploy.getStorageEngine();
|
||||
this.autoTunable = EntityType.ORM == entityType && (beanFinder == null);
|
||||
this.autoTunable = beanFinder == null && (entityType == EntityType.ORM || entityType == EntityType.VIEW);
|
||||
|
||||
// helper object used to derive lists of properties
|
||||
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
|
||||
@@ -752,6 +757,18 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
softDeleteByIdSql = null;
|
||||
softDeleteByIdInSql = null;
|
||||
}
|
||||
initNaturalKey();
|
||||
}
|
||||
|
||||
private void initNaturalKey() {
|
||||
final String[] naturalKey = cacheHelp.getNaturalKey();
|
||||
if (naturalKey != null && naturalKey.length != 0) {
|
||||
BeanProperty[] props = new BeanProperty[naturalKey.length];
|
||||
for (int i = 0; i < naturalKey.length; i++) {
|
||||
props[i] = getBeanProperty(naturalKey[i]);
|
||||
}
|
||||
this.beanNaturalKey = new BeanNaturalKey(naturalKey, props);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasCircularImportedId() {
|
||||
@@ -884,6 +901,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
}
|
||||
}
|
||||
|
||||
public void metricPersistBatch(PersistRequest.Type type, long startNanos, int size) {
|
||||
iudMetrics.addBatch(type, startNanos, size);
|
||||
}
|
||||
|
||||
public void metricPersistNoBatch(PersistRequest.Type type, long startNanos) {
|
||||
iudMetrics.addNoBatch(type, startNanos);
|
||||
}
|
||||
|
||||
public void merge(EntityBean bean, EntityBean existing) {
|
||||
|
||||
EntityBeanIntercept fromEbi = bean._ebean_getIntercept();
|
||||
@@ -1322,10 +1347,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the natural key properties.
|
||||
* Return the natural key.
|
||||
*/
|
||||
public String[] getNaturalKey() {
|
||||
return cacheHelp.getNaturalKey();
|
||||
public BeanNaturalKey getNaturalKey() {
|
||||
return beanNaturalKey;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1658,10 +1683,11 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return new DeployUpdateParser(this).parse(ormUpdateStatement);
|
||||
}
|
||||
|
||||
void collectQueryPlans(QueryPlanRequest request) {
|
||||
void queryPlanInit(QueryPlanInit request, List<MetaQueryPlan> list) {
|
||||
for (CQueryPlan queryPlan : queryPlanCache.values()) {
|
||||
if (request.includeLabel(queryPlan.getLabel())) {
|
||||
queryPlan.collectQueryPlan(request);
|
||||
if (request.includeHash(queryPlan.getHash())) {
|
||||
queryPlan.queryPlanInit(request.getThresholdMicros());
|
||||
list.add(queryPlan.createMeta(null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1670,9 +1696,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
* Visit all the ORM query plan metrics (includes UpdateQuery with updates and deletes).
|
||||
*/
|
||||
public void visitMetrics(MetricVisitor visitor) {
|
||||
iudMetrics.visit(visitor);
|
||||
for (CQueryPlan queryPlan : queryPlanCache.values()) {
|
||||
if (!queryPlan.isEmptyStats()) {
|
||||
visitor.visitOrmQuery(queryPlan.getSnapshot(visitor.isReset()));
|
||||
visitor.visitQuery(queryPlan.getSnapshot(visitor.isReset()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1689,19 +1716,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
/**
|
||||
* Trim query plans not used since the passed in epoch time.
|
||||
*/
|
||||
List<CQueryPlan> trimQueryPlans(long unusedSince) {
|
||||
|
||||
List<CQueryPlan> list = new ArrayList<>();
|
||||
|
||||
void trimQueryPlans(long unusedSince) {
|
||||
Iterator<CQueryPlan> it = queryPlanCache.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
CQueryPlan queryPlan = it.next();
|
||||
if (queryPlan.getLastQueryTime() < unusedSince) {
|
||||
it.remove();
|
||||
list.add(queryPlan);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -386,7 +386,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
|
||||
Map<Object, Object> beanDataMap = beanCache.getAll(keys);
|
||||
if (beanLog.isTraceEnabled()) {
|
||||
beanLog.trace(" GET MANY {}({}) - hits:{}", cacheName, ids, beanDataMap.keySet());
|
||||
beanLog.trace(" MGET {}({}) - hits:{}", cacheName, ids, beanDataMap.keySet());
|
||||
}
|
||||
|
||||
BeanCacheResult<T> result = new BeanCacheResult<>();
|
||||
@@ -412,7 +412,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
Map<Object, Object> naturalKeyMap = naturalKeyCache.getAll(keys);
|
||||
|
||||
if (natLog.isTraceEnabled()) {
|
||||
natLog.trace(" LOOKUP Many {}({}) - hits:{}", cacheName, keys, naturalKeyMap);
|
||||
natLog.trace(" MLOOKUP {}({}) - hits:{}", cacheName, keys, naturalKeyMap);
|
||||
}
|
||||
|
||||
BeanCacheResult<T> result = new BeanCacheResult<>();
|
||||
@@ -429,7 +429,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
Set<Object> ids = new HashSet<>(naturalKeyMap.values());
|
||||
Map<Object, Object> beanDataMap = beanCache.getAll(ids);
|
||||
if (beanLog.isTraceEnabled()) {
|
||||
beanLog.trace(" GET MANY {}({}) - hits:{}", cacheName, ids, beanDataMap.keySet());
|
||||
beanLog.trace(" MGET {}({}) - hits:{}", cacheName, ids, beanDataMap.keySet());
|
||||
}
|
||||
// process the hits into beans etc
|
||||
for (Map.Entry<Object, Object> entry : beanDataMap.entrySet()) {
|
||||
@@ -550,13 +550,13 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
}
|
||||
if (beanLog.isDebugEnabled()) {
|
||||
beanLog.debug(" PUT ALL {}({})", cacheName, map.keySet());
|
||||
beanLog.debug(" MPUT {}({})", cacheName, map.keySet());
|
||||
}
|
||||
getBeanCache().putAll(map);
|
||||
|
||||
if (natKeys != null && !natKeys.isEmpty()) {
|
||||
if (natLog.isDebugEnabled()) {
|
||||
natLog.debug(" PUT ALL {}({}, {})", cacheName, naturalKey, natKeys.keySet());
|
||||
natLog.debug(" MPUT {}({}, {})", cacheName, naturalKey, natKeys.keySet());
|
||||
}
|
||||
naturalKeyCache.putAll(natKeys);
|
||||
}
|
||||
@@ -733,7 +733,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
void beanCacheApplyInvalidate(Collection<String> keys) {
|
||||
if (beanCache != null) {
|
||||
if (beanLog.isDebugEnabled()) {
|
||||
beanLog.debug(" REMOVE {}({})", cacheName, keys);
|
||||
beanLog.debug(" MREMOVE {}({})", cacheName, keys);
|
||||
}
|
||||
beanCache.removeAll(new HashSet<>(keys));
|
||||
}
|
||||
@@ -756,7 +756,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
Map<Object, Object> hits = getBeanCache().getAll(ebis.keySet());
|
||||
|
||||
if (beanLog.isTraceEnabled()) {
|
||||
beanLog.trace(" LOAD ALL {}({}) - got hits ({})", cacheName, ebis.keySet(), hits.size());
|
||||
beanLog.trace(" MLOAD {}({}) - got hits ({})", cacheName, ebis.keySet(), hits.size());
|
||||
}
|
||||
|
||||
Set<EntityBeanIntercept> loaded = new HashSet<>();
|
||||
@@ -771,7 +771,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
|
||||
if (lazyLoadProperty > -1 && !cacheData.isLoaded(propertyName)) {
|
||||
if (beanLog.isTraceEnabled()) {
|
||||
beanLog.trace(" LOAD {}({}) - cache miss on property({})", cacheName, key, propertyName);
|
||||
beanLog.trace(" load {}({}) - cache miss on property({})", cacheName, key, propertyName);
|
||||
}
|
||||
iterator.remove();
|
||||
|
||||
@@ -779,13 +779,13 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
CachedBeanDataToBean.load(desc, ebi.getOwner(), cacheData, context);
|
||||
loaded.add(ebi);
|
||||
if (beanLog.isDebugEnabled()) {
|
||||
beanLog.debug(" LOAD {}({}) - hit", cacheName, key);
|
||||
beanLog.debug(" load {}({}) - hit", cacheName, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ebis.isEmpty() && beanLog.isTraceEnabled()) {
|
||||
beanLog.trace(" LOAD {}({}) - cache miss", cacheName, ebis.keySet());
|
||||
beanLog.trace(" load {}({}) - cache miss", cacheName, ebis.keySet());
|
||||
}
|
||||
|
||||
return loaded;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user