mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-09-20 11:17:36 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
032f4de857 | ||
|
|
59431814ce | ||
|
|
e7194055be | ||
|
|
806c7cd752 | ||
|
|
dfc7f92160 | ||
|
|
26351325a8 | ||
|
|
2d37f9d01e | ||
|
|
d3fd03ce5b | ||
|
|
a8e92791cd | ||
|
|
94e63cc30f | ||
|
|
3567263250 | ||
|
|
bc03f8d516 | ||
|
|
7035ff20eb | ||
|
|
f38479022a | ||
|
|
986cc905d8 | ||
|
|
8f3fe688cb | ||
|
|
eee26d9ed3 | ||
|
|
44bd60e586 | ||
|
|
20d7af6d25 | ||
|
|
e5aeda9d4e | ||
|
|
46bb1ca060 | ||
|
|
0652167101 | ||
|
|
6633293151 | ||
|
|
9e603f2848 | ||
|
|
fff345ffc8 | ||
|
|
dd1fe845aa | ||
|
|
80451c3c62 | ||
|
|
2d199737aa |
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-clickhouse</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-db2</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-h2</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-hana</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-mariadb</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-mysql</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -47,19 +47,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-net-postgis-types</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-nuodb</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-oracle</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -47,19 +47,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-pgvector-types</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -47,19 +47,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis-types</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-sqlite</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-sqlserver</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -41,7 +41,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jackson-mapper</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -60,13 +60,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-all</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>composites</artifactId>
|
||||
|
||||
@@ -11,6 +11,7 @@ Step-by-step guides for common Ebean tasks (Maven setup, database config, query
|
||||
Key guides (fetch and follow when performing the relevant task):
|
||||
- Maven POM setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-maven-pom.md
|
||||
- Database configuration: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-database-config.md
|
||||
- Migrate to `Database.builder()`: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/migrating-to-database-builder.md
|
||||
- Write queries with query beans: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/writing-ebean-query-beans.md
|
||||
- Persisting and transactions: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/persisting-and-transactions-with-ebean.md
|
||||
- Test container setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-test-container.md
|
||||
|
||||
@@ -18,6 +18,18 @@ existing Maven project. Complete the steps in order.
|
||||
| 2 | [Test container setup](add-ebean-postgres-test-container.md) | Start a PostgreSQL (or PostGIS) Docker container for tests using `@TestScope @Factory` with Avaje Inject; verify the test database works with `mvn verify` before adding production configuration |
|
||||
| 3 | [Database configuration](add-ebean-postgres-database-config.md) | Configure the production Ebean `Database` bean using `DataSourceBuilder` and `DatabaseBuilder` with Avaje Inject |
|
||||
|
||||
## Migration & upgrades
|
||||
|
||||
| Guide | Description |
|
||||
|-------|-------------|
|
||||
| [Migrate to `Database.builder()`](migrating-to-database-builder.md) | Replace legacy `new DatabaseConfig()` and `DatabaseFactory.create(...)` code with `Database.builder()` and `DatabaseBuilder.build()`. Includes common rewrites, fluent builder equivalents, and manual-review cases for semi-automated upgrades |
|
||||
|
||||
## Observability
|
||||
|
||||
| Guide | Description |
|
||||
|-------|-------------|
|
||||
| [Ebean OpenTelemetry tracing](add-ebean-opentelemetry.md) | Add `ebean-opentelemetry`, register `GlobalOpenTelemetry` once before Ebean databases are built, and troubleshoot missing spans or double-registration errors |
|
||||
|
||||
## Entity beans
|
||||
|
||||
| Guide | Description |
|
||||
@@ -133,8 +145,10 @@ tasks are at: https://github.com/ebean-orm/ebean/tree/HEAD/docs/guides/
|
||||
Key guides (fetch and follow these when performing the relevant task):
|
||||
- Maven POM setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-maven-pom.md
|
||||
- Database configuration: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-database-config.md
|
||||
- Migrate to `Database.builder()`: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/migrating-to-database-builder.md
|
||||
- Write queries with query beans: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/writing-ebean-query-beans.md
|
||||
- Immutable bean cache for read-only references: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/immutable-bean-cache.md
|
||||
- Ebean OpenTelemetry tracing: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-opentelemetry.md
|
||||
- Persisting and transactions: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/persisting-and-transactions-with-ebean.md
|
||||
- Test container setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-test-container.md
|
||||
- DB migration generation: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-db-migration-generation.md
|
||||
@@ -158,6 +172,7 @@ tasks are at: https://github.com/ebean-orm/ebean/tree/HEAD/docs/guides/
|
||||
Key guides (fetch and follow these when performing the relevant task):
|
||||
- Maven POM setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-maven-pom.md
|
||||
- Database configuration: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-database-config.md
|
||||
- Migrate to `Database.builder()`: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/migrating-to-database-builder.md
|
||||
- Write queries with query beans: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/writing-ebean-query-beans.md
|
||||
- Persisting and transactions: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/persisting-and-transactions-with-ebean.md
|
||||
- Test container setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-test-container.md
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
# Guide: Add Ebean OpenTelemetry tracing
|
||||
|
||||
## Purpose
|
||||
|
||||
This guide explains how to enable Ebean transaction tracing with OpenTelemetry and,
|
||||
most importantly, how to order startup so Ebean sees the intended global
|
||||
OpenTelemetry instance.
|
||||
|
||||
Use this guide when adding `ebean-opentelemetry`, diagnosing missing Ebean spans,
|
||||
or fixing `GlobalOpenTelemetry` double-registration errors.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
`ebean-opentelemetry` provides an Ebean profiling handler that creates transaction
|
||||
spans as children of the current active OpenTelemetry span. It does not create
|
||||
top-level request, job, or Lambda invocation spans by itself.
|
||||
|
||||
The handler resolves its tracer from `GlobalOpenTelemetry` when the Ebean
|
||||
`Database` is configured. For that reason, the application must build and register
|
||||
the OpenTelemetry SDK before any Ebean `Database` beans are created.
|
||||
|
||||
Rules of thumb:
|
||||
|
||||
- Register the global OpenTelemetry instance once.
|
||||
- Register it before building Ebean databases.
|
||||
- Model that ordering as a real DI dependency.
|
||||
- Do not call `GlobalOpenTelemetry.set(...)` or `buildAndRegisterGlobal()` in
|
||||
multiple places.
|
||||
|
||||
---
|
||||
|
||||
## Step 1 - Add the dependency
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-opentelemetry</artifactId>
|
||||
<version>${ebean.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
The module registers the Ebean OpenTelemetry profile handler via `ServiceLoader`.
|
||||
No manual Ebean plugin registration is normally required.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 - Build OpenTelemetry before Ebean databases
|
||||
|
||||
Create one application-owned OpenTelemetry bean. For example, when using
|
||||
`avaje-metrics-otel`:
|
||||
|
||||
```java
|
||||
import io.avaje.config.Configuration;
|
||||
import io.avaje.inject.Bean;
|
||||
import io.avaje.inject.Factory;
|
||||
import io.avaje.metrics.otel.MetricsOpenTelemetry;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Factory
|
||||
class OpenTelemetryConfig {
|
||||
|
||||
@Bean
|
||||
OpenTelemetry openTelemetry(Configuration config) {
|
||||
return MetricsOpenTelemetry.builder()
|
||||
.endpoint(config.get("otel.endpoint"))
|
||||
.serviceName(config.get("otel.serviceName", "orders"))
|
||||
.deploymentEnvironmentName(config.get("app.env", "local"))
|
||||
.meterInterval(Duration.ofSeconds(30))
|
||||
.traceInterval(Duration.ofSeconds(30))
|
||||
.buildAndRegisterGlobal();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you build the SDK directly, use the same principle: create the SDK once and
|
||||
register that instance globally before any Ebean databases are built.
|
||||
|
||||
---
|
||||
|
||||
## Step 3 - Make database beans depend on OpenTelemetry
|
||||
|
||||
In DI code, make the `Database` bean method accept `OpenTelemetry`. This parameter
|
||||
is intentionally present to make startup order deterministic: OpenTelemetry is
|
||||
created and registered before Ebean configures the database and profile handler.
|
||||
|
||||
```java
|
||||
import io.avaje.config.Configuration;
|
||||
import io.avaje.inject.Bean;
|
||||
import io.avaje.inject.Factory;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.datasource.DataSourceBuilder;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
|
||||
@Factory
|
||||
class DatabaseConfig {
|
||||
|
||||
@Bean
|
||||
Database database(OpenTelemetry openTelemetry, Configuration config) {
|
||||
var dataSource = DataSourceBuilder.create()
|
||||
.url(config.get("db.url"))
|
||||
.username(config.get("db.username"))
|
||||
.password(config.get("db.password"));
|
||||
|
||||
return Database.builder()
|
||||
.name("db")
|
||||
.dataSourceBuilder(dataSource)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For Spring, use the same dependency shape: either inject `OpenTelemetry` into the
|
||||
database `@Bean` method or use `@DependsOn` to ensure the OpenTelemetry bean is
|
||||
initialized first.
|
||||
|
||||
Do not invert the dependency by making OpenTelemetry depend on the Ebean
|
||||
`Database`. That creates a startup cycle and can still initialize Ebean before the
|
||||
global OpenTelemetry instance is ready.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 - Create a parent span at the application boundary
|
||||
|
||||
Ebean transaction spans are child spans. They are only created when a recording
|
||||
OpenTelemetry span is active on the current thread.
|
||||
|
||||
Use HTTP server instrumentation, Lambda instrumentation, or an application-level
|
||||
root span around the top-level request/job boundary. Ebean will then attach
|
||||
transaction spans beneath that current span.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `GlobalOpenTelemetry.set has already been called`
|
||||
|
||||
This usually means more than one component is trying to register a global SDK, or
|
||||
some startup path touched the global before the application registered its SDK.
|
||||
|
||||
Fixes:
|
||||
|
||||
1. Keep exactly one `buildAndRegisterGlobal()` / `GlobalOpenTelemetry.set(...)`
|
||||
call in the application.
|
||||
2. Build that OpenTelemetry bean before Ebean `Database` beans.
|
||||
3. Remove duplicate OTEL setup from tests, helper factories, or secondary modules.
|
||||
|
||||
### No Ebean spans appear
|
||||
|
||||
Check:
|
||||
|
||||
1. `ebean-opentelemetry` is on the runtime classpath.
|
||||
2. OpenTelemetry is registered before Ebean databases are built.
|
||||
3. There is a current recording parent span when Ebean transactions run.
|
||||
4. Sampling is not dropping the parent trace.
|
||||
@@ -1,4 +1,4 @@
|
||||
# Guide: Add Ebean ORM (PostgreSQL) to an Existing Maven Project — Step 2: Database Configuration
|
||||
# Guide: Add Ebean ORM (PostgreSQL) to an Existing Maven Project — Step 3: Database Configuration
|
||||
|
||||
## Purpose
|
||||
|
||||
@@ -148,7 +148,6 @@ Database database(Configuration config) {
|
||||
return Database.builder()
|
||||
.name("db")
|
||||
.dataSourceBuilder(dataSource)
|
||||
.skipDataSourceCheck(true)
|
||||
.build();
|
||||
}
|
||||
```
|
||||
@@ -156,6 +155,11 @@ Database database(Configuration config) {
|
||||
If the project has a dedicated config-wrapper class (a `@Component` that reads config
|
||||
keys), accept it as a parameter instead of `Configuration`.
|
||||
|
||||
> **Note:** Injecting `Configuration` requires that `avaje-config` is properly wired
|
||||
> into the DI context. If you encounter "No dependency provided for
|
||||
> io.avaje.config.Configuration" errors, use `Config.get(...)` static access instead
|
||||
> (as shown in Step 2).
|
||||
|
||||
---
|
||||
|
||||
## Step 4 (Optional) — Add a read-only datasource
|
||||
|
||||
@@ -85,7 +85,7 @@ already exist:
|
||||
```xml
|
||||
<properties>
|
||||
<!-- add this line; use latest stable from https://github.com/ebean-orm/ebean/releases -->
|
||||
<ebean.version>17.2.0</ebean.version>
|
||||
<ebean.version>17.5.0</ebean.version>
|
||||
</properties>
|
||||
```
|
||||
|
||||
@@ -141,8 +141,17 @@ for Postgres test instances:
|
||||
<version>${ebean.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
The `io.avaje:junit` bundle includes JUnit Jupiter (API + engine) and AssertJ,
|
||||
avoiding the need to declare those dependencies separately.
|
||||
|
||||
---
|
||||
|
||||
## Step 4b — Add DI framework dependencies (if applicable)
|
||||
@@ -156,12 +165,12 @@ annotation processor. Skip this step if the user chose Spring or no DI.
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-inject</artifactId>
|
||||
<version>11.5</version>
|
||||
<version>12.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-inject-test</artifactId>
|
||||
<version>11.5</version>
|
||||
<version>12.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
```
|
||||
@@ -185,7 +194,7 @@ the final `<annotationProcessorPaths>` block should include both:
|
||||
<path> <!-- generate avaje-inject DI code -->
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-inject-generator</artifactId>
|
||||
<version>11.5</version>
|
||||
<version>12.5</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
```
|
||||
|
||||
@@ -433,3 +433,13 @@ mkdir -p ~/.ebean && touch ~/.ebean/ignore-docker-shutdown
|
||||
```
|
||||
|
||||
On CI servers, omit this file so containers are cleaned up after each build.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- **Add `TestEntityBuilder`** to your test configuration for rapid test data creation
|
||||
with auto-populated random values. See `testing-with-testentitybuilder.md`.
|
||||
- **Proceed to Step 3** — production database configuration
|
||||
(`add-ebean-postgres-database-config.md`). Verify this step passes with
|
||||
`mvn verify` before continuing.
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
# Guide: Migrate from `DatabaseConfig` / `DatabaseFactory` to `Database.builder()`
|
||||
|
||||
## Purpose
|
||||
|
||||
This guide shows how to migrate legacy programmatic database creation code from:
|
||||
|
||||
- `new DatabaseConfig()`
|
||||
- `DatabaseFactory.create(...)`
|
||||
- old `setXxx(...)` builder-style configuration methods
|
||||
|
||||
…to the preferred builder-based style using:
|
||||
|
||||
- `Database.builder()`
|
||||
- fluent `DatabaseBuilder` methods such as `name(...)`, `register(...)`, and `defaultDatabase(...)`
|
||||
- `DatabaseBuilder.build()`
|
||||
|
||||
Use this guide when upgrading older Ebean setup code or when building an automated/semi-automated migration.
|
||||
|
||||
---
|
||||
|
||||
## Preferred pattern
|
||||
|
||||
Prefer code shaped like this:
|
||||
|
||||
```java
|
||||
Database database = Database.builder()
|
||||
.name("db")
|
||||
.loadFromProperties()
|
||||
.dataSourceBuilder(dataSource)
|
||||
.register(true)
|
||||
.defaultDatabase(true)
|
||||
.build();
|
||||
```
|
||||
|
||||
The important points are:
|
||||
|
||||
1. Start with `Database.builder()`
|
||||
2. Configure via `DatabaseBuilder`
|
||||
3. Finish with `.build()`
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Replace `new DatabaseConfig()` with `Database.builder()`
|
||||
|
||||
### Before
|
||||
|
||||
```java
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName("db");
|
||||
config.loadFromProperties();
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
```java
|
||||
DatabaseBuilder config = Database.builder()
|
||||
.name("db")
|
||||
.loadFromProperties();
|
||||
```
|
||||
|
||||
### Notes
|
||||
|
||||
- Prefer the `DatabaseBuilder` type for local variables and parameters when possible.
|
||||
- If existing code only uses standard builder methods, this change is usually mechanical.
|
||||
- If existing code later reads configuration back, use `config.settings()`.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Replace `DatabaseFactory.create(config)` with `config.build()`
|
||||
|
||||
### Before
|
||||
|
||||
```java
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName("db");
|
||||
config.loadFromProperties();
|
||||
Database database = DatabaseFactory.create(config);
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
```java
|
||||
DatabaseBuilder config = Database.builder()
|
||||
.name("db")
|
||||
.loadFromProperties();
|
||||
Database database = config.build();
|
||||
```
|
||||
|
||||
### Short form
|
||||
|
||||
```java
|
||||
Database database = Database.builder()
|
||||
.name("db")
|
||||
.loadFromProperties()
|
||||
.build();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Replace `DatabaseFactory.create("name")`
|
||||
|
||||
### Before
|
||||
|
||||
```java
|
||||
Database database = DatabaseFactory.create("other");
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
```java
|
||||
Database database = Database.builder()
|
||||
.name("other")
|
||||
.loadFromProperties()
|
||||
.build();
|
||||
```
|
||||
|
||||
### Important
|
||||
|
||||
For **named databases**, set `.name("...")` before `.loadFromProperties()` so the named configuration is loaded.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Replace legacy `setXxx(...)` methods with fluent builder methods
|
||||
|
||||
`DatabaseBuilder` already exposes preferred fluent names for most configuration methods.
|
||||
Use those names when migrating older setup code.
|
||||
|
||||
| Legacy call | Preferred call |
|
||||
|---|---|
|
||||
| `setName("db")` | `name("db")` |
|
||||
| `setRegister(false)` | `register(false)` |
|
||||
| `setDefaultServer(false)` | `defaultDatabase(false)` |
|
||||
| `setContainerConfig(cfg)` | `containerConfig(cfg)` |
|
||||
| `setDbSchema("app")` | `dbSchema("app")` |
|
||||
| `setDataSourceConfig(ds)` | `dataSourceBuilder(ds)` |
|
||||
| `setReadOnlyDataSourceConfig(ro)` | `readOnlyDataSourceBuilder(ro)` |
|
||||
| `setRunMigration(true)` | `runMigration(true)` |
|
||||
| `setDisableClasspathSearch(true)` | `disableClasspathSearch(true)` |
|
||||
| `setPersistBatch(batch)` | `persistBatch(batch)` |
|
||||
|
||||
### Full example
|
||||
|
||||
#### Before
|
||||
|
||||
```java
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName("db");
|
||||
config.setRegister(false);
|
||||
config.setDefaultServer(false);
|
||||
config.setDataSourceConfig(dataSource);
|
||||
Database database = DatabaseFactory.create(config);
|
||||
```
|
||||
|
||||
#### After
|
||||
|
||||
```java
|
||||
Database database = Database.builder()
|
||||
.name("db")
|
||||
.register(false)
|
||||
.defaultDatabase(false)
|
||||
.dataSourceBuilder(dataSource)
|
||||
.build();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Verify semantics after migration
|
||||
|
||||
The migration should preserve behavior, but verify these points:
|
||||
|
||||
- `register(true)` is still the default
|
||||
- `defaultDatabase(true)` is still the default
|
||||
- call `loadFromProperties()` if the old code loaded configuration from properties
|
||||
- for named databases, set the name before loading properties
|
||||
- explicit entity registration via `addClass(...)` / `addAll(...)` is unchanged
|
||||
- custom datasource wiring via `dataSourceBuilder(...)` and `readOnlyDataSourceBuilder(...)` is unchanged
|
||||
|
||||
---
|
||||
|
||||
## Manual-review cases
|
||||
|
||||
These cases are **not** simple search-and-replace migrations and should be reviewed manually:
|
||||
|
||||
### `DatabaseFactory.createWithContextClassLoader(...)`
|
||||
|
||||
There is no direct builder shorthand for this today. Keep this as-is for now and migrate the surrounding builder configuration first.
|
||||
|
||||
### `DatabaseFactory.initialiseContainer(...)`
|
||||
|
||||
This is a container lifecycle concern, not a normal database-builder call. Keep it as-is unless you are intentionally moving the `ContainerConfig` onto the first builder via `containerConfig(...)`.
|
||||
|
||||
### `DatabaseFactory.shutdown()`
|
||||
|
||||
This is also a lifecycle concern rather than normal builder setup. Leave it alone unless you are making a deliberate lifecycle change.
|
||||
|
||||
### Variables or method signatures typed as `DatabaseConfig`
|
||||
|
||||
If the code only uses standard builder operations, switch the type to `DatabaseBuilder`.
|
||||
If the code depends on implementation-specific `DatabaseConfig` methods, review it manually.
|
||||
|
||||
### Code that needs read access to builder settings
|
||||
|
||||
Use:
|
||||
|
||||
```java
|
||||
DatabaseBuilder builder = Database.builder();
|
||||
DatabaseBuilder.Settings settings = builder.settings();
|
||||
```
|
||||
|
||||
rather than relying on the concrete `DatabaseConfig` type only to read getters.
|
||||
|
||||
---
|
||||
|
||||
## Automation notes for AI agents and bulk refactors
|
||||
|
||||
This migration is a good candidate for semi-automated upgrading.
|
||||
|
||||
### Safe mechanical rewrites
|
||||
|
||||
These are usually safe to rewrite automatically:
|
||||
|
||||
- `new DatabaseConfig()` → `Database.builder()`
|
||||
- `DatabaseFactory.create(builder)` → `builder.build()`
|
||||
- `DatabaseFactory.create("name")` → `Database.builder().name("name").loadFromProperties().build()`
|
||||
- legacy `setXxx(...)` calls → preferred fluent builder methods
|
||||
|
||||
### Flag for manual review
|
||||
|
||||
Automatically flag, but do not blindly rewrite:
|
||||
|
||||
- `DatabaseFactory.createWithContextClassLoader(...)`
|
||||
- `DatabaseFactory.initialiseContainer(...)`
|
||||
- `DatabaseFactory.shutdown()`
|
||||
- parameters, fields, or return types declared as `DatabaseConfig`
|
||||
- any use that clearly depends on `DatabaseConfig` implementation details rather than `DatabaseBuilder`
|
||||
|
||||
---
|
||||
|
||||
## Related guides
|
||||
|
||||
- [Database configuration](add-ebean-postgres-database-config.md) — preferred modern setup style using `Database.builder()`
|
||||
- [Guide index](README.md) — full list of Ebean setup and migration guides
|
||||
@@ -0,0 +1,333 @@
|
||||
# Immutable Bean Cache — notes on multi-level / remote caching
|
||||
|
||||
These notes capture design thoughts for a possible future multi-level immutable bean cache,
|
||||
where immutable beans may be cached remotely (for example Redis or a Postgres cache table)
|
||||
in addition to an in-JVM cache.
|
||||
|
||||
## Current important constraint
|
||||
|
||||
`AssocOneHelp.read()` now uses `ImmutableBeanCache.getIfPresent(id)` as a direct-hit fast path.
|
||||
|
||||
That means:
|
||||
|
||||
- `getIfPresent(id)` is on the **row read hot path**
|
||||
- it must remain **cheap and local**
|
||||
- it should **not** perform network I/O
|
||||
- it should **not** deserialize remote payloads
|
||||
- it should **not** trigger loading or record misses
|
||||
|
||||
## Strong recommendation
|
||||
|
||||
For any multi-level cache design:
|
||||
|
||||
- **L1 cache** = in-JVM cache of already materialized immutable beans
|
||||
- **L2 cache** = remote/shared cache of serialized immutable snapshots
|
||||
- **Loader** = Ebean query using the configured fetch group
|
||||
|
||||
With that split:
|
||||
|
||||
- `getIfPresent(id)` => **L1 only**
|
||||
- `getAll(ids)` => batch through **L1 -> L2 -> loader**
|
||||
|
||||
This preserves the `AssocOneHelp` fast path.
|
||||
|
||||
---
|
||||
|
||||
## Snapshot mindset
|
||||
|
||||
Remote cache entries should be treated as **immutable snapshots**, not just arbitrary beans.
|
||||
|
||||
A cached value is specific to:
|
||||
|
||||
- bean type
|
||||
- bean id
|
||||
- tenant (if multi-tenant)
|
||||
- fetch-group / cache identity
|
||||
- serializer/schema version
|
||||
|
||||
This matters because a `Customer` cached with:
|
||||
|
||||
- `select("name,version")`
|
||||
|
||||
is not equivalent to a `Customer` cached with:
|
||||
|
||||
- `select("name,version").fetch("billingAddress", "line1,city")`
|
||||
|
||||
## Key design recommendation
|
||||
|
||||
Remote keys should include at least:
|
||||
|
||||
- bean type
|
||||
- bean id
|
||||
- tenant id (if applicable)
|
||||
- cache/fetch-group identity
|
||||
- optionally serializer/schema version
|
||||
|
||||
Example shape:
|
||||
|
||||
- `immutable:Customer:basic:42`
|
||||
- `immutable:Customer:withAddresses:42`
|
||||
|
||||
---
|
||||
|
||||
## Recommended multi-level flow
|
||||
|
||||
### L1
|
||||
|
||||
Store actual read-only `EntityBean` instances.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- support `getIfPresent(id)`
|
||||
- avoid repeated deserialize cost
|
||||
- avoid network calls on row read path
|
||||
|
||||
### L2
|
||||
|
||||
Store serialized immutable snapshots.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- batch lookup only
|
||||
- support cross-JVM sharing
|
||||
- feed L1 with materialized immutable beans
|
||||
|
||||
### Loader
|
||||
|
||||
Use the existing query/fetch-group-based loader for misses.
|
||||
|
||||
### Suggested `getAll(ids)` flow
|
||||
|
||||
1. Check L1
|
||||
2. Batch remaining ids to L2
|
||||
3. Deserialize L2 hits into read-only beans
|
||||
4. Put those beans into L1
|
||||
5. Batch remaining misses to DB loader
|
||||
6. Freeze / ensure read-only beans
|
||||
7. Write through to L2
|
||||
8. Put into L1
|
||||
9. Negative-cache true misses if desired
|
||||
|
||||
---
|
||||
|
||||
## Invalidation is more important than serialization
|
||||
|
||||
Things to think about:
|
||||
|
||||
- update/delete invalidation across JVMs
|
||||
- local L1 invalidation when L2 entry is removed
|
||||
- ordering relative to DB commit
|
||||
- multiple cache instances for the same bean type but different fetch groups
|
||||
- tenant-scoped invalidation
|
||||
|
||||
Recommended direction:
|
||||
|
||||
- keep current immutable-cache invalidation semantics
|
||||
- add a remote invalidation/event mechanism for L2-backed caches
|
||||
- each JVM should evict affected L1 entries when notified
|
||||
|
||||
Examples:
|
||||
|
||||
- Redis: pub/sub or streams
|
||||
- Postgres cache table: NOTIFY/listen, polling, or invalidation table/outbox pattern
|
||||
|
||||
---
|
||||
|
||||
## Serialization format considerations
|
||||
|
||||
## JSON
|
||||
|
||||
### Pros
|
||||
|
||||
- human readable / debuggable
|
||||
- easier rolling upgrades
|
||||
- field-name based, so generally more tolerant of schema evolution
|
||||
- good fit for Redis strings or Postgres JSONB
|
||||
- easier operational debugging
|
||||
|
||||
### Cons
|
||||
|
||||
- larger payloads
|
||||
- more CPU to serialize/deserialize
|
||||
- nested graphs / enums / dates / inheritance need disciplined handling
|
||||
|
||||
## Kryo / generic binary serialization
|
||||
|
||||
### Pros
|
||||
|
||||
- smaller payloads
|
||||
- often faster than JSON
|
||||
- can preserve object graphs efficiently
|
||||
|
||||
### Cons
|
||||
|
||||
- more fragile across versions and rolling deploys
|
||||
- class registration / compatibility pain
|
||||
- harder to inspect/debug
|
||||
- tighter coupling to JVM/class layout
|
||||
- riskier for long-lived shared cache entries
|
||||
|
||||
## Recommendation
|
||||
|
||||
For a first remote/shared implementation:
|
||||
|
||||
- prefer **JSON** or another self-describing structured format
|
||||
- if a binary format is later needed, prefer a stable schema-based format over generic object-graph serialization
|
||||
- **do not start with Kryo** unless short-lived entries and tight deployment coordination are acceptable
|
||||
|
||||
---
|
||||
|
||||
## What to serialize
|
||||
|
||||
Avoid thinking in terms of serializing arbitrary live entity bean graphs directly.
|
||||
|
||||
A cleaner model is:
|
||||
|
||||
- serialize a **snapshot representation**
|
||||
- deserialize into a fresh entity bean
|
||||
- mark loaded properties appropriately
|
||||
- freeze / ensure read-only state
|
||||
- store the resulting materialized bean in L1
|
||||
|
||||
This gives more control over:
|
||||
|
||||
- loaded-property semantics
|
||||
- read-only state
|
||||
- subtype handling
|
||||
- schema/version evolution
|
||||
|
||||
## Practical recommendation
|
||||
|
||||
Remote cache entries should represent exactly the configured fetch-group snapshot.
|
||||
|
||||
That means:
|
||||
|
||||
- cache what the fetch group loaded
|
||||
- include nested associations loaded by that fetch group
|
||||
- treat it as a self-contained immutable snapshot
|
||||
|
||||
This is simpler than trying to normalize the graph into many remote cache fragments and re-link it later.
|
||||
|
||||
---
|
||||
|
||||
## Redis vs Postgres cache table
|
||||
|
||||
## Redis
|
||||
|
||||
### Good for
|
||||
|
||||
- low latency
|
||||
- batch lookup via MGET / pipelining
|
||||
- TTL/eviction support
|
||||
- natural shared-cache use case
|
||||
|
||||
### Tradeoffs
|
||||
|
||||
- extra infrastructure
|
||||
- memory cost
|
||||
- invalidation/event coordination still required
|
||||
|
||||
## Postgres cache table (including unlogged-style approach)
|
||||
|
||||
### Good for
|
||||
|
||||
- simpler ops if Postgres is already present
|
||||
- easy batch lookup with `IN (...)`
|
||||
- fewer moving parts than introducing Redis
|
||||
|
||||
### Tradeoffs
|
||||
|
||||
- slower than Redis for hot shared-cache usage
|
||||
- adds pressure to Postgres
|
||||
- TTL/cleanup becomes application responsibility
|
||||
- still network/database I/O, so should remain off the `getIfPresent()` hot path
|
||||
|
||||
## Recommendation
|
||||
|
||||
- if the goal is a serious shared L2 cache, Redis is the more natural fit
|
||||
- if the goal is pragmatic shared caching with minimal extra infrastructure, Postgres can work but should still be treated as L2-only
|
||||
|
||||
---
|
||||
|
||||
## Versioning / evolution
|
||||
|
||||
Whatever serializer is used, include versioning information.
|
||||
|
||||
Useful dimensions:
|
||||
|
||||
- serializer/schema version
|
||||
- cache implementation version
|
||||
- fetch-group/cache identity version
|
||||
|
||||
This helps when:
|
||||
|
||||
- fields are added/removed
|
||||
- graph shape changes
|
||||
- fetch-group definitions evolve
|
||||
|
||||
---
|
||||
|
||||
## Compression
|
||||
|
||||
If remote snapshots become large:
|
||||
|
||||
- compress only above a size threshold
|
||||
- avoid compressing tiny payloads
|
||||
|
||||
This is especially relevant for JSON in Redis or Postgres L2.
|
||||
|
||||
---
|
||||
|
||||
## Observability
|
||||
|
||||
A multi-level cache should expose at least:
|
||||
|
||||
- L1 hit rate
|
||||
- L2 hit rate
|
||||
- DB loader rate
|
||||
- deserialize failures
|
||||
- invalidation counts
|
||||
- average payload size
|
||||
- cold-start amplification
|
||||
|
||||
Without this, it will be hard to judge whether the remote cache is helping.
|
||||
|
||||
---
|
||||
|
||||
## Overall recommended architecture
|
||||
|
||||
### Recommended model
|
||||
|
||||
- **L1**: actual read-only `EntityBean` instances
|
||||
- **L2**: serialized immutable snapshots
|
||||
- **Loader**: fetch-group-based DB query
|
||||
|
||||
### Method responsibilities
|
||||
|
||||
- `getIfPresent(id)` => **L1 only**
|
||||
- `getAll(ids)` => **L1 + L2 + DB loader** in batches
|
||||
|
||||
This aligns well with the current `AssocOneHelp` optimization and keeps the row-read path fast.
|
||||
|
||||
---
|
||||
|
||||
## Bottom line
|
||||
|
||||
If/when multi-level immutable caching is explored, the main points to preserve are:
|
||||
|
||||
1. keep `getIfPresent()` local-only
|
||||
2. do remote work only in batched `getAll()`
|
||||
3. key by type + id + tenant + fetch-group/cache identity
|
||||
4. treat remote values as immutable snapshots
|
||||
5. prefer JSON/self-describing format first
|
||||
6. be cautious with generic binary serializers like Kryo
|
||||
|
||||
---
|
||||
|
||||
## Possible follow-up
|
||||
|
||||
If this becomes active design work later, consider promoting these notes into one of:
|
||||
|
||||
- a dedicated design note under `docs/notes/`
|
||||
- a GitHub issue / discussion for design iteration
|
||||
- a lightweight ADR if this becomes a committed architectural direction
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
|
||||
@@ -23,11 +23,18 @@ import java.util.concurrent.Callable;
|
||||
/**
|
||||
* Provides the API for fetching and saving beans to a particular database.
|
||||
*
|
||||
* <h5>Constructing a Database</h5>
|
||||
* <p>
|
||||
* Databases are typically constructed via {@link #builder()} and {@link DatabaseBuilder#build()}.
|
||||
* They can also be automatically constructed on demand using configuration information in
|
||||
* the application.properties file. The underlying implementation is provided by
|
||||
* {@link DatabaseFactory}.
|
||||
*
|
||||
* <h5>Registration with the DB singleton</h5>
|
||||
* <p>
|
||||
* When a Database instance is created it can be registered with the DB
|
||||
* singleton (see {@link DatabaseConfig#setRegister(boolean)}). The DB
|
||||
* singleton is essentially a map of Database's that have been registered
|
||||
* When a Database instance is created it can be registered with the {@link DB}
|
||||
* singleton (see {@link DatabaseBuilder#register(boolean)}). The {@link DB}
|
||||
* singleton is essentially a map of {@link Database}'s that have been registered
|
||||
* with it.
|
||||
* <p>
|
||||
* The Database can then be retrieved later via {@link DB#byName(String)}.
|
||||
@@ -35,16 +42,10 @@ import java.util.concurrent.Callable;
|
||||
* <h5>The 'default' Database</h5>
|
||||
* <p>
|
||||
* One Database can be designated as the 'default' or 'primary' Database
|
||||
* (see {@link DatabaseConfig#setDefaultServer(boolean)}). Many methods on DB
|
||||
* (see {@link DatabaseBuilder#defaultDatabase(boolean)}). Many methods on {@link DB}
|
||||
* such as {@link DB#find(Class)} etc are actually just a convenient way to
|
||||
* call methods on the 'default/primary' Database.
|
||||
*
|
||||
* <h5>Constructing a Database</h5>
|
||||
* <p>
|
||||
* Databases are constructed by the DatabaseFactory. They can be created
|
||||
* programmatically via {@link DatabaseFactory#create(DatabaseBuilder)} or they
|
||||
* can be automatically constructed on demand using configuration information in
|
||||
* the application.properties file.
|
||||
*
|
||||
* <h5>Example: Get a Database</h5>
|
||||
* <pre>{@code
|
||||
@@ -80,6 +81,7 @@ import java.util.concurrent.Callable;
|
||||
* method. Example: a single thread requires more than one transaction.
|
||||
*
|
||||
* @see DB
|
||||
* @see DatabaseBuilder
|
||||
* @see DatabaseFactory
|
||||
* @see DatabaseConfig
|
||||
*/
|
||||
@@ -94,11 +96,13 @@ public interface Database {
|
||||
* // from application.properties / application.yaml
|
||||
*
|
||||
* Database db = Database.builder()
|
||||
* .name("db")
|
||||
* .loadFromProperties()
|
||||
* .build();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
static DatabaseBuilder builder() {
|
||||
return new DatabaseConfig();
|
||||
}
|
||||
|
||||
@@ -723,19 +723,6 @@ public interface DatabaseBuilder {
|
||||
@Deprecated
|
||||
DatabaseBuilder setReadAuditPrepare(ReadAuditPrepare readAuditPrepare);
|
||||
|
||||
/**
|
||||
* Set the configuration for profiling.
|
||||
*/
|
||||
default DatabaseBuilder profilingConfig(ProfilingConfig profilingConfig) {
|
||||
return setProfilingConfig(profilingConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated migrate to {@link #profilingConfig(ProfilingConfig)}.
|
||||
*/
|
||||
@Deprecated
|
||||
DatabaseBuilder setProfilingConfig(ProfilingConfig profilingConfig);
|
||||
|
||||
/**
|
||||
* Set the suffix appended to the base table to derive the view that contains the union
|
||||
* of the base table and the history table in order to support asOf queries.
|
||||
@@ -995,7 +982,7 @@ public interface DatabaseBuilder {
|
||||
* <p>
|
||||
* Use this to override the default known aggregation functions.
|
||||
*/
|
||||
DatabaseConfig aggregateFormulaContext(AggregateFormulaContext aggregateFormulaContext);
|
||||
DatabaseBuilder aggregateFormulaContext(AggregateFormulaContext aggregateFormulaContext);
|
||||
|
||||
/**
|
||||
* Set to true if all DB column and table names should use quoted identifiers.
|
||||
@@ -2234,7 +2221,7 @@ public interface DatabaseBuilder {
|
||||
*
|
||||
* @param includeLabelInSql When true include a SQL inline comment in generated SELECT queries.
|
||||
*/
|
||||
DatabaseConfig includeLabelInSql(boolean includeLabelInSql);
|
||||
DatabaseBuilder includeLabelInSql(boolean includeLabelInSql);
|
||||
|
||||
/**
|
||||
* Set the naming convention to apply to metrics names.
|
||||
@@ -2252,7 +2239,7 @@ public interface DatabaseBuilder {
|
||||
/**
|
||||
* Sets the length check mode.
|
||||
*/
|
||||
DatabaseConfig lengthCheck(LengthCheck lengthCheck);
|
||||
DatabaseBuilder lengthCheck(LengthCheck lengthCheck);
|
||||
|
||||
/**
|
||||
* Provides read access (getters) for the DatabaseBuilder configuration
|
||||
@@ -2490,11 +2477,6 @@ public interface DatabaseBuilder {
|
||||
*/
|
||||
TenantCatalogProvider getTenantCatalogProvider();
|
||||
|
||||
/**
|
||||
* Return the configuration for profiling.
|
||||
*/
|
||||
ProfilingConfig getProfilingConfig();
|
||||
|
||||
/**
|
||||
* Return the DB schema to use.
|
||||
*/
|
||||
|
||||
@@ -8,18 +8,18 @@ import jakarta.persistence.PersistenceException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Creates Database instances.
|
||||
* Low-level factory for creating {@link Database} instances.
|
||||
* <p>
|
||||
* This uses either DatabaseConfig or properties in the application.properties file to
|
||||
* configure and create a Database instance.
|
||||
* Most applications should prefer {@link Database#builder()} together with {@link DatabaseBuilder#build()}.
|
||||
* This factory remains for legacy creation entry points plus container lifecycle methods.
|
||||
* <p>
|
||||
* The Database instance can either be registered with the DB singleton or
|
||||
* not. The DB singleton effectively holds a map of Database by a name.
|
||||
* If the Database is registered with the DB singleton you can retrieve it
|
||||
* The Database instance can either be registered with the {@link DB} singleton or
|
||||
* not. The {@link DB} singleton effectively holds a map of {@link Database} by name.
|
||||
* If the Database is registered with the {@link DB} singleton you can retrieve it
|
||||
* later via {@link DB#byName(String)}.
|
||||
* <p>
|
||||
* One Database can be nominated as the 'default/primary' Database. Many
|
||||
* methods on the DB singleton such as {@link DB#find(Class)} are just a
|
||||
* methods on the {@link DB} singleton such as {@link DB#find(Class)} are just a
|
||||
* convenient way of using the 'default/primary' Database.
|
||||
*/
|
||||
public final class DatabaseFactory {
|
||||
@@ -36,7 +36,8 @@ public final class DatabaseFactory {
|
||||
* Initialise the container with clustering configuration.
|
||||
* <p>
|
||||
* Call this prior to creating any Database instances or alternatively set the
|
||||
* ContainerConfig on the DatabaseConfig when creating the first Database instance.
|
||||
* {@link ContainerConfig} on the first {@link DatabaseBuilder} via
|
||||
* {@link DatabaseBuilder#containerConfig(ContainerConfig)}.
|
||||
*/
|
||||
public static void initialiseContainer(ContainerConfig containerConfig) {
|
||||
lock.lock();
|
||||
@@ -48,8 +49,11 @@ public final class DatabaseFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using properties to configure the database.
|
||||
* Create using configuration loaded from properties for the given database name.
|
||||
*
|
||||
* @deprecated migrate to {@code Database.builder().name(name).loadFromProperties().build()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Database create(String name) {
|
||||
lock.lock();
|
||||
try {
|
||||
@@ -60,18 +64,9 @@ public final class DatabaseFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the DatabaseConfig object to configure the database.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DatabaseConfig config = new DatabaseConfig();
|
||||
* config.setName("db");
|
||||
* config.loadProperties();
|
||||
*
|
||||
* Database database = DatabaseFactory.create(config);
|
||||
*
|
||||
* }</pre>
|
||||
* @deprecated migrate to {@link DatabaseBuilder#build()}.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public static Database create(DatabaseBuilder builder) {
|
||||
lock.lock();
|
||||
try {
|
||||
@@ -97,7 +92,8 @@ public final class DatabaseFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the DatabaseConfig additionally specifying a classLoader to use as the context class loader.
|
||||
* Create using the {@link DatabaseBuilder}, additionally specifying a classLoader to use as the
|
||||
* context class loader.
|
||||
*/
|
||||
public static Database createWithContextClassLoader(DatabaseBuilder config, ClassLoader classLoader) {
|
||||
lock.lock();
|
||||
|
||||
@@ -92,6 +92,7 @@ final class DbContext {
|
||||
/**
|
||||
* Read, create and put of Databases.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private Database getWithCreate(String name) {
|
||||
lock.lock();
|
||||
try {
|
||||
|
||||
@@ -205,4 +205,20 @@ public interface UpdateQuery<T> {
|
||||
*/
|
||||
int update();
|
||||
|
||||
/**
|
||||
* Return the timeout used to execute this statement.
|
||||
*/
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* Set a timeout on this query.
|
||||
* <p>
|
||||
* This will typically result in a call to setQueryTimeout() on a
|
||||
* preparedStatement. If the timeout occurs an exception will be thrown - this
|
||||
* will be a SQLException wrapped up in a PersistenceException.
|
||||
* </p>
|
||||
*
|
||||
* @param secs the query timeout limit in seconds. Zero means there is no limit.
|
||||
*/
|
||||
UpdateQuery<T> setTimeout(int secs);
|
||||
}
|
||||
|
||||
@@ -31,38 +31,15 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a Database.
|
||||
* <p>
|
||||
* Used to programmatically construct an Database and optionally register it
|
||||
* with the DB singleton.
|
||||
* <p>
|
||||
* If you just use DB thout this programmatic configuration Ebean will read
|
||||
* the application.properties file and take the configuration from there. This usually
|
||||
* includes searching the class path and automatically registering any entity
|
||||
* classes and listeners etc.
|
||||
* <pre>{@code
|
||||
*
|
||||
* DatabaseConfig config = new DatabaseConfig();
|
||||
*
|
||||
* // read the ebean.properties and load
|
||||
* // those settings into this DatabaseConfig object
|
||||
* config.loadFromProperties();
|
||||
*
|
||||
* // explicitly register the entity beans to avoid classpath scanning
|
||||
* config.addClass(Customer.class);
|
||||
* config.addClass(User.class);
|
||||
*
|
||||
* Database db = DatabaseFactory.create(config);
|
||||
*
|
||||
* }</pre>
|
||||
* Deprecated migrate to {@link Database#builder()} rather than constructing {@code DatabaseConfig} directly.
|
||||
*
|
||||
* <p>
|
||||
* Note that DatabaseConfigProvider provides a standard Java ServiceLoader mechanism that can
|
||||
* be used to apply configuration to the DatabaseConfig.
|
||||
* Note that {@link DatabaseConfigProvider} provides a standard Java ServiceLoader mechanism that can
|
||||
* be used to apply configuration to the {@link DatabaseBuilder}.
|
||||
*
|
||||
* @author emcgreal
|
||||
* @author rbygrave
|
||||
* @see DatabaseFactory
|
||||
* @see Database#builder()
|
||||
*/
|
||||
public class DatabaseConfig implements DatabaseBuilder.Settings {
|
||||
|
||||
@@ -539,8 +516,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
||||
*/
|
||||
private SlowQueryListener slowQueryListener;
|
||||
|
||||
private ProfilingConfig profilingConfig = new ProfilingConfig();
|
||||
|
||||
/**
|
||||
* The mappingLocations for searching xml mapping.
|
||||
*/
|
||||
@@ -560,12 +535,14 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
||||
private Function<String, String> metricNaming = MetricNamingMatch.INSTANCE;
|
||||
|
||||
/**
|
||||
* Construct a Database Configuration for programmatically creating an Database.
|
||||
* @deprecated migrate to {@link Database#builder()} and configure the returned {@link DatabaseBuilder}.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public DatabaseConfig() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
public Database build() {
|
||||
return DatabaseFactory.create(this);
|
||||
}
|
||||
@@ -1028,17 +1005,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfilingConfig getProfilingConfig() {
|
||||
return profilingConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatabaseConfig setProfilingConfig(ProfilingConfig profilingConfig) {
|
||||
this.profilingConfig = profilingConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDbSchema() {
|
||||
return dbSchema;
|
||||
@@ -2137,7 +2103,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
|
||||
*/
|
||||
protected void loadSettings(PropertiesWrapper p) {
|
||||
dbSchema = p.get("dbSchema", dbSchema);
|
||||
profilingConfig.loadSettings(p, name);
|
||||
platformConfig.loadSettings(p);
|
||||
if (platformConfig.isAllQuotedIdentifiers()) {
|
||||
adjustNamingConventionForAllQuoted();
|
||||
|
||||
@@ -3,14 +3,14 @@ package io.ebean.config;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
|
||||
/**
|
||||
* Provides a ServiceLoader based mechanism to configure a DatabaseConfig.
|
||||
* Provides a ServiceLoader based mechanism to configure a {@link DatabaseBuilder}.
|
||||
* <p>
|
||||
* Provide an implementation and register it via the standard Java ServiceLoader mechanism
|
||||
* via a file at <code>META-INF/services/io.ebean.config.DatabaseConfigProvider</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you are using a DI container like Spring or Guice you are unlikely to use this but instead use a
|
||||
* spring specific configuration. When we are not using a DI container we may use this mechanism to
|
||||
* spring specific configuration. When we are not using a DI container we may use this mechanism to
|
||||
* explicitly register the entity beans and avoid classpath scanning.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
@@ -18,7 +18,7 @@ import io.ebean.DatabaseBuilder;
|
||||
* public class EbeanConfigProvider implements DatabaseConfigProvider {
|
||||
*
|
||||
* @Override
|
||||
* public void apply(DatabaseConfig config) {
|
||||
* public void apply(DatabaseBuilder config) {
|
||||
*
|
||||
* // register the entity bean classes explicitly
|
||||
* config.addClass(Customer.class);
|
||||
@@ -32,10 +32,9 @@ import io.ebean.DatabaseBuilder;
|
||||
public interface DatabaseConfigProvider {
|
||||
|
||||
/**
|
||||
* Apply the configuration to the DatabaseConfig.
|
||||
* Apply the configuration to the {@link DatabaseBuilder}.
|
||||
* <p>
|
||||
* Typically we explicitly register entity bean classes and thus avoid classpath scanning.
|
||||
* </p>
|
||||
*/
|
||||
void apply(DatabaseBuilder config);
|
||||
}
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* Configuration for transaction profiling.
|
||||
*/
|
||||
public class ProfilingConfig {
|
||||
|
||||
/**
|
||||
* When true transaction profiling is enabled.
|
||||
*/
|
||||
private boolean enabled;
|
||||
|
||||
/**
|
||||
* Set true for verbose mode.
|
||||
*/
|
||||
private boolean verbose;
|
||||
|
||||
/**
|
||||
* The minimum transaction execution time to be included in profiling.
|
||||
*/
|
||||
private long minimumMicros;
|
||||
|
||||
/**
|
||||
* A specific set of profileIds to include in profiling.
|
||||
*/
|
||||
private int[] includeProfileIds = {};
|
||||
|
||||
/**
|
||||
* The number of profiles to write per file.
|
||||
*/
|
||||
private long profilesPerFile = 1000;
|
||||
|
||||
private String directory = "profiling";
|
||||
|
||||
/**
|
||||
* Return true if transaction profiling is enabled.
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to enable transaction profiling.
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if verbose mode is used.
|
||||
*/
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to use verbose mode.
|
||||
*/
|
||||
public void setVerbose(boolean verbose) {
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum transaction execution to be included in profiling.
|
||||
*/
|
||||
public long getMinimumMicros() {
|
||||
return minimumMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum transaction execution to be included in profiling.
|
||||
*/
|
||||
public void setMinimumMicros(long minimumMicros) {
|
||||
this.minimumMicros = minimumMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specific set of profileIds to include in profiling.
|
||||
* When not set all transactions with profileIds are included.
|
||||
*/
|
||||
public int[] getIncludeProfileIds() {
|
||||
return includeProfileIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific set of profileIds to include in profiling.
|
||||
* When not set all transactions with profileIds are included.
|
||||
*/
|
||||
public void setIncludeProfileIds(int[] includeProfileIds) {
|
||||
this.includeProfileIds = includeProfileIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of profiles to write to a single file.
|
||||
*/
|
||||
public long getProfilesPerFile() {
|
||||
return profilesPerFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of profiles to write to a single file.
|
||||
*/
|
||||
public void setProfilesPerFile(long profilesPerFile) {
|
||||
this.profilesPerFile = profilesPerFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the directory profiling files are put into.
|
||||
*/
|
||||
public String getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the directory profiling files are put into.
|
||||
*/
|
||||
public void setDirectory(String directory) {
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load setting from properties.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper p, String name) {
|
||||
|
||||
enabled = p.getBoolean("profiling", enabled);
|
||||
verbose = p.getBoolean("profiling.verbose", verbose);
|
||||
|
||||
directory = p.get("profiling.directory", directory);
|
||||
profilesPerFile = p.getLong("profiling.profilesPerFile", profilesPerFile);
|
||||
minimumMicros = p.getLong("profiling.minimumMicros", minimumMicros);
|
||||
|
||||
String includeIds = p.get("profiling.includeProfileIds");
|
||||
if (includeIds != null) {
|
||||
includeProfileIds = parseIds(includeIds);
|
||||
}
|
||||
}
|
||||
|
||||
private int[] parseIds(String includeIds) {
|
||||
|
||||
String[] ids = includeIds.split(",");
|
||||
int[] vals = new int[ids.length];
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
vals[i] = Integer.parseInt(ids[i]);
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,23 @@ public interface MetaInfoManager {
|
||||
/**
|
||||
* Return the metrics for the database instance.
|
||||
* <p>
|
||||
* This will reset the metrics (reset counters back to zero etc) and
|
||||
* will only return the non-empty metrics.
|
||||
* This is equivalent to {@link #collectMetrics(boolean)} with reset set to true.
|
||||
* It will reset the metrics (reset counters back to zero etc) and will only return
|
||||
* the non-empty metrics.
|
||||
* </p>
|
||||
*/
|
||||
ServerMetrics collectMetrics();
|
||||
|
||||
/**
|
||||
* Return the metrics for the database instance using the given reset behavior.
|
||||
* <p>
|
||||
* When reset is false, count and total values remain cumulative between collections.
|
||||
* </p>
|
||||
*/
|
||||
default ServerMetrics collectMetrics(boolean reset) {
|
||||
return collectMetrics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit the metrics resetting and collecting/reporting as desired.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class MetaInfoManagerTest {
|
||||
|
||||
@Test
|
||||
void collectMetricsBooleanDefaultsToCollectMetrics() {
|
||||
ServerMetrics metrics = new BasicMetricVisitor();
|
||||
MetaInfoManager manager = new MetaInfoManager() {
|
||||
@Override
|
||||
public ServerMetrics collectMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMetrics(MetricVisitor visitor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicMetricVisitor visitBasic() {
|
||||
return new BasicMetricVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetAllMetrics() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request) {
|
||||
return List.of();
|
||||
}
|
||||
};
|
||||
|
||||
assertThat(manager.collectMetrics(false)).isSameAs(metrics);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-bench</artifactId>
|
||||
|
||||
+28
-28
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean bom</name>
|
||||
@@ -89,25 +89,25 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -125,13 +125,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jackson-mapper</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -155,37 +155,37 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-spring-txn</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- platforms -->
|
||||
@@ -193,91 +193,91 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-clickhouse</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-db2</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-h2</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-hana</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-mariadb</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-mysql</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-nuodb</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-oracle</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis-types</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-pgvector</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-pgvector-types</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-sqlite</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-sqlserver</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
<artifactId>ebean-core-json</artifactId>
|
||||
<name>ebean-core-json</name>
|
||||
@@ -16,7 +16,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
@@ -16,7 +16,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
+7
-7
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
@@ -22,13 +22,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-json</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -52,7 +52,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -165,21 +165,21 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-h2</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-sqlserver</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -10,18 +10,6 @@ import org.jspecify.annotations.Nullable;
|
||||
*/
|
||||
public interface SpiProfileHandler {
|
||||
|
||||
/**
|
||||
* Process the collected transaction profiling information.
|
||||
* <p>
|
||||
* Note that profileId and totalMicros are part of the profilingData but passed separately as the handler
|
||||
* may filter what it processed based on this information (ignore short transactions, only process specific
|
||||
* profileId transactions etc).
|
||||
* </p>
|
||||
*
|
||||
* @param transactionProfile The transaction profile that has just been collected
|
||||
*/
|
||||
void collectTransactionProfile(TransactionProfile transactionProfile);
|
||||
|
||||
/**
|
||||
* Create a profiling stream for this transaction, or return null to not profile this transaction.
|
||||
* <p>
|
||||
|
||||
@@ -35,14 +35,17 @@ final class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
|
||||
@Override
|
||||
public ServerMetrics collectMetrics() {
|
||||
return visitBasic();
|
||||
return collectMetrics(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetrics collectMetrics(boolean reset) {
|
||||
return collectBasic(reset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicMetricVisitor visitBasic() {
|
||||
BasicMetricVisitor basic = new BasicMetricVisitor(server.name(), naming);
|
||||
visitMetrics(basic);
|
||||
return basic;
|
||||
return collectBasic(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,6 +53,12 @@ final class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
server.visitMetrics(new ResetVisitor());
|
||||
}
|
||||
|
||||
private BasicMetricVisitor collectBasic(boolean reset) {
|
||||
BasicMetricVisitor basic = new BasicMetricVisitor(server.name(), naming, reset, true, true, true);
|
||||
visitMetrics(basic);
|
||||
return basic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor that resets the statistics but doesn't collect them.
|
||||
*/
|
||||
|
||||
@@ -405,12 +405,7 @@ public final class InternalConfiguration {
|
||||
if (handler != null) {
|
||||
return plugin(handler);
|
||||
}
|
||||
|
||||
ProfilingConfig profilingConfig = config.getProfilingConfig();
|
||||
if (!profilingConfig.isEnabled()) {
|
||||
return new NoopProfileHandler();
|
||||
}
|
||||
return plugin(new DefaultProfileHandler(profilingConfig));
|
||||
return new NoopProfileHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,9 +116,12 @@ public final class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
getGeneratedKeys();
|
||||
}
|
||||
postExecute();
|
||||
addTimingMetrics();
|
||||
list.clear();
|
||||
transaction.profileEvent(this);
|
||||
try {
|
||||
addTimingMetrics();
|
||||
transaction.profileEvent(this);
|
||||
} finally {
|
||||
list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void addTimingMetrics() {
|
||||
|
||||
@@ -19,9 +19,7 @@ final class DTimeMetricStats implements TimedMetricStats {
|
||||
this.collected = collected;
|
||||
this.count = count;
|
||||
this.total = total;
|
||||
// collection is racy so sanitize the max value if it has not been set
|
||||
// this most likely would happen when count = 1 so max = mean
|
||||
this.max = max != Long.MIN_VALUE ? max : (count < 1 ? 0 : Math.round(total / count));
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,7 +17,7 @@ final class DTimedMetric implements TimedMetric {
|
||||
private final String name;
|
||||
private final LongAdder count = new LongAdder();
|
||||
private final LongAdder total = new LongAdder();
|
||||
private final LongAccumulator max = new LongAccumulator(Math::max, Long.MIN_VALUE);
|
||||
private final LongAccumulator max = new LongAccumulator(Math::max, 0);
|
||||
private boolean collected;
|
||||
private String reportName;
|
||||
|
||||
@@ -84,11 +84,8 @@ final class DTimedMetric implements TimedMetric {
|
||||
*/
|
||||
private DTimeMetricStats stats(boolean reset, String name, long countSum) {
|
||||
try {
|
||||
if (reset) {
|
||||
return new DTimeMetricStats(name, collected, countSum, total.sumThenReset(), max.getThenReset());
|
||||
} else {
|
||||
return new DTimeMetricStats(name, collected, countSum, total.sum(), max.get());
|
||||
}
|
||||
final long totalSum = reset ? total.sumThenReset() : total.sum();
|
||||
return new DTimeMetricStats(name, collected, countSum, totalSum, max.getThenReset());
|
||||
} finally {
|
||||
collected = true;
|
||||
}
|
||||
|
||||
@@ -569,7 +569,7 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
|
||||
public void profile() {
|
||||
transaction()
|
||||
.profileStream()
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), loadedBeanCount, query.profileId(), query.getGeneratedSql());
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), loadedBeanCount, query.profileId(), queryPlan.hash(), query.getGeneratedSql());
|
||||
}
|
||||
|
||||
QueryIterator<T> readIterate(int bufferSize, OrmQueryRequest<T> request) {
|
||||
|
||||
+1
-1
@@ -165,7 +165,7 @@ final class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent, Ca
|
||||
public void profile() {
|
||||
transaction()
|
||||
.profileStream()
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), rowCount, query.profileId(), query.getGeneratedSql());
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), rowCount, query.profileId(), queryPlan.hash(), query.getGeneratedSql());
|
||||
}
|
||||
|
||||
Set<String> dependentTables() {
|
||||
|
||||
@@ -137,7 +137,7 @@ final class CQueryRowCount implements SpiProfileTransactionEvent, CancelableQuer
|
||||
public void profile() {
|
||||
transaction()
|
||||
.profileStream()
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), rowCount, query.profileId(), query.getGeneratedSql());
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), rowCount, query.profileId(), queryPlan.hash(), query.getGeneratedSql());
|
||||
}
|
||||
|
||||
Set<String> dependentTables() {
|
||||
|
||||
@@ -115,7 +115,7 @@ final class CQueryUpdate implements SpiProfileTransactionEvent, CancelableQuery
|
||||
public void profile() {
|
||||
transaction()
|
||||
.profileStream()
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), rowCount, query.profileId(), query.getGeneratedSql());
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), rowCount, query.profileId(), queryPlan.hash(), query.getGeneratedSql());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -84,4 +84,15 @@ public final class DefaultUpdateQuery<T> implements UpdateQuery<T> {
|
||||
public int update() {
|
||||
return query.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeout() {
|
||||
return query.timeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateQuery<T> setTimeout(int secs) {
|
||||
query.setTimeout(secs);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ public final class OrmQueryProperties implements Serializable {
|
||||
}
|
||||
|
||||
private static String buildImmutableQueryPlanHashSuffix(FetchConfig fetchConfig) {
|
||||
return fetchConfig == null ? "" : "/c" + fetchConfig.hashCode();
|
||||
return fetchConfig == null ? "}" : "/c" + fetchConfig.hashCode() + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -468,7 +468,6 @@ public final class OrmQueryProperties implements Serializable {
|
||||
filterMany.queryPlanHash(builder);
|
||||
}
|
||||
builder.append(immutableHashSuffix);
|
||||
builder.append('}');
|
||||
}
|
||||
|
||||
private static void appendSet(StringBuilder builder, Set<String> values) {
|
||||
|
||||
-271
@@ -1,271 +0,0 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.config.ProfilingConfig;
|
||||
import io.ebean.plugin.Plugin;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebean.util.IOUtils;
|
||||
import io.ebeaninternal.api.CoreLog;
|
||||
import io.ebeaninternal.api.SpiProfileHandler;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.lang.System.Logger.Level.*;
|
||||
import static java.time.temporal.ChronoField.*;
|
||||
|
||||
/**
|
||||
* Default profile handler.
|
||||
* <p>
|
||||
* Uses ConcurrentLinkedQueue to minimise contention on threads calling collectTransactionProfile().
|
||||
* <p>
|
||||
* Uses a sleep backoff on the single threaded consumer that reads the profiles and writes them to files.
|
||||
*/
|
||||
public final class DefaultProfileHandler implements SpiProfileHandler, Plugin {
|
||||
|
||||
private static final System.Logger log = CoreLog.internal;
|
||||
private static final DateTimeFormatter DTF;
|
||||
|
||||
static {
|
||||
DTF = new DateTimeFormatterBuilder()
|
||||
.parseCaseInsensitive()
|
||||
.appendValue(YEAR, 4)
|
||||
.appendValue(MONTH_OF_YEAR, 2)
|
||||
.appendValue(DAY_OF_MONTH, 2)
|
||||
.appendLiteral('-')
|
||||
.appendValue(HOUR_OF_DAY, 2)
|
||||
.appendValue(MINUTE_OF_HOUR, 2)
|
||||
.appendValue(SECOND_OF_MINUTE, 2)
|
||||
.appendLiteral('-')
|
||||
.appendValue(MILLI_OF_SECOND, 3)
|
||||
.toFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Low contention choice.
|
||||
*/
|
||||
private final Queue<TransactionProfile> queue = new ConcurrentLinkedQueue<>();
|
||||
private final ExecutorService executor;
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final File dir;
|
||||
private final long minMicros;
|
||||
private final long profilesPerFile;
|
||||
private final boolean verbose;
|
||||
private volatile boolean shutdown;
|
||||
private long profileCounter;
|
||||
/**
|
||||
* Slow down polling of transaction profiling queue.
|
||||
*/
|
||||
private int sleepBackoff;
|
||||
private Writer out;
|
||||
|
||||
public DefaultProfileHandler(ProfilingConfig config) {
|
||||
this.verbose = config.isVerbose();
|
||||
this.minMicros = config.getMinimumMicros();
|
||||
this.profilesPerFile = config.getProfilesPerFile();
|
||||
|
||||
// dedicated single threaded executor for consuming the
|
||||
// profiling and writing it to file(s)
|
||||
this.executor = Executors.newSingleThreadExecutor();
|
||||
this.dir = new File(config.getDirectory());
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
log.log(ERROR, "failed to mkdirs " + dir.getAbsolutePath());
|
||||
}
|
||||
incrementFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Low contention adding the transaction profile to the queue.
|
||||
* Minimise the impact to the normal transaction processing (threads).
|
||||
*/
|
||||
@Override
|
||||
public void collectTransactionProfile(TransactionProfile transactionProfile) {
|
||||
queue.add(transactionProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a ProfileStream, or null if location is null (implicit transactions
|
||||
* are not profiled by the default file-based handler).
|
||||
*/
|
||||
@Override
|
||||
public ProfileStream createProfileStream(@Nullable ProfileLocation location, String label) {
|
||||
if (location == null) {
|
||||
return null;
|
||||
}
|
||||
return new DefaultProfileStream(location, verbose);
|
||||
}
|
||||
|
||||
private void flushCurrentFile() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
out = null;
|
||||
} catch (IOException e) {
|
||||
log.log(ERROR, "Failed to flush and close transaction profiling file ", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to the next file to write to.
|
||||
*/
|
||||
private void incrementFile() {
|
||||
lock.lock();
|
||||
try {
|
||||
flushCurrentFile();
|
||||
try {
|
||||
String now = DTF.format(LocalDateTime.now());
|
||||
File file = new File(dir, "txprofile-" + now + ".tprofile");
|
||||
out = IOUtils.newWriter(file);
|
||||
} catch (IOException e) {
|
||||
log.log(ERROR, "Not expected", e);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main loop for polling the queue and processing profiling messages.
|
||||
*/
|
||||
private void collect() {
|
||||
try {
|
||||
while (!shutdown) {
|
||||
TransactionProfile profile = queue.poll();
|
||||
if (profile == null) {
|
||||
sleep();
|
||||
|
||||
} else if (include(profile)) {
|
||||
write(profile);
|
||||
}
|
||||
}
|
||||
flushCurrentFile();
|
||||
} catch (Exception e) {
|
||||
log.log(WARNING, "Error on collect", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the profile to the current file.
|
||||
*/
|
||||
private void write(TransactionProfile profile) {
|
||||
try {
|
||||
sleepBackoff = 0;
|
||||
++profileCounter;
|
||||
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
|
||||
// header
|
||||
sb.append(profile.getStartTime()).append(' ')
|
||||
.append(profile.getLabel()).append(' ')
|
||||
.append(profile.getTotalMicros()).append(' ');
|
||||
|
||||
// summary
|
||||
appendSummary(profile, sb);
|
||||
|
||||
out.write(sb.toString());
|
||||
if (verbose) {
|
||||
out.write(' ');
|
||||
out.write(profile.getData());
|
||||
}
|
||||
out.write('\n');
|
||||
|
||||
if (profileCounter % profilesPerFile == 0) {
|
||||
incrementFile();
|
||||
log.log(DEBUG, "profiled {0} transactions", profileCounter);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.log(WARNING, "Error writing transaction profiling", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendSummary(TransactionProfile profile, StringBuilder sb) {
|
||||
|
||||
TransactionProfile.Summary summary = profile.getSummary();
|
||||
|
||||
sb.append("z:").append(rate(profile.getTotalMicros(), summary.persistCount + summary.queryCount)).append(' ');
|
||||
sb.append("p:").append(rate(summary.persistMicros, summary.persistBeans)).append(' ');
|
||||
sb.append("q:").append(rate(summary.queryMicros, summary.queryCount)).append(' ');
|
||||
|
||||
sb.append("qm:").append(summary.queryMax).append(' ');
|
||||
sb.append("qt:").append(summary.queryMicros).append(' ');
|
||||
sb.append("qc:").append(summary.queryCount).append(' ');
|
||||
sb.append("qb:").append(summary.queryBeans).append(' ');
|
||||
|
||||
sb.append("pt:").append(summary.persistMicros).append(' ');
|
||||
sb.append("pc:").append(summary.persistCount).append(' ');
|
||||
sb.append("pb:").append(summary.persistBeans).append(' ');
|
||||
sb.append("po:").append(summary.persistOneCount).append(' ');
|
||||
sb.append("pz:").append(rate(summary.persistBeans, summary.persistCount));
|
||||
}
|
||||
|
||||
private int rate(long micros, long count) {
|
||||
return count < 1 ? 0 : (int) (micros / count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the profile should be included (or false for ignored).
|
||||
*/
|
||||
private boolean include(TransactionProfile profile) {
|
||||
return profile.getTotalMicros() >= minMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep backing off towards 250 millis when there is no activity.
|
||||
* This seems to be simple and decent for our queue consumer.
|
||||
*/
|
||||
private void sleep() {
|
||||
try {
|
||||
// backoff sleep when nothing is happening
|
||||
int sleepFor = Math.min(++sleepBackoff, 250);
|
||||
Thread.sleep(sleepFor);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(SpiServer server) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void online(boolean online) {
|
||||
if (online) {
|
||||
executor.submit(this::collect);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
shutdown = true;
|
||||
log.log(TRACE, "shutting down");
|
||||
try {
|
||||
executor.shutdown();
|
||||
if (!executor.awaitTermination(4, TimeUnit.SECONDS)) {
|
||||
log.log(INFO, "Shut down timeout exceeded. Terminating profiling consumer thread.");
|
||||
executor.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
log.log(WARNING, "Interrupt on shutdown", e);
|
||||
}
|
||||
flushCurrentFile();
|
||||
}
|
||||
}
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Default transaction profiling event collection.
|
||||
*/
|
||||
public final class DefaultProfileStream implements ProfileStream {
|
||||
|
||||
private final long startNanos;
|
||||
private final StringBuilder buffer;
|
||||
private final TransactionProfile profile;
|
||||
private final TransactionProfile.Summary summary;
|
||||
|
||||
DefaultProfileStream(@Nullable ProfileLocation location, boolean verbose) {
|
||||
this.startNanos = System.nanoTime();
|
||||
this.profile = new TransactionProfile(System.currentTimeMillis(), location);
|
||||
this.summary = profile.getSummary();
|
||||
this.buffer = (verbose) ? new StringBuilder(200) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time offset from the beginning of the transaction.
|
||||
*/
|
||||
@Override
|
||||
public long offset() {
|
||||
return ((System.nanoTime() - startNanos) / 1_000L);
|
||||
}
|
||||
|
||||
private long exeMicros(long offset) {
|
||||
return offset() - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a query execution event.
|
||||
*/
|
||||
@Override
|
||||
public void addQueryEvent(String event, long offset, String beanName, int beanCount, String queryId, String sql) {
|
||||
long micros = exeMicros(offset);
|
||||
summary.addQuery(micros, beanCount);
|
||||
if (buffer != null) {
|
||||
add(micros, event, offset, beanName, beanCount, queryId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a persist event.
|
||||
*/
|
||||
@Override
|
||||
public void addPersistEvent(String event, long offset, String beanName, int beanCount) {
|
||||
long micros = exeMicros(offset);
|
||||
summary.addPersist(micros, beanCount);
|
||||
if (buffer != null) {
|
||||
add(micros, event, offset, beanName, beanCount, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the commit/rollback event.
|
||||
*/
|
||||
@Override
|
||||
public void addEvent(String event, long offset) {
|
||||
long micros = exeMicros(offset);
|
||||
summary.commitMicros = micros;
|
||||
if (buffer != null) {
|
||||
buffer.append(event).append(',');
|
||||
buffer.append(offset).append(',');
|
||||
buffer.append(micros).append(';');
|
||||
}
|
||||
}
|
||||
|
||||
private void add(long micros, String event, long offset, String beanName, int beanCount, String queryId) {
|
||||
buffer.append(event).append(',');
|
||||
buffer.append(offset).append(',');
|
||||
buffer.append(micros).append(',');
|
||||
buffer.append(beanName).append(',');
|
||||
buffer.append(beanCount).append(',');
|
||||
buffer.append(queryId).append(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* End the transaction profiling.
|
||||
*/
|
||||
@Override
|
||||
public void end(TransactionManager manager, String label) {
|
||||
profile.setTotalMicros(offset());
|
||||
if (buffer != null) {
|
||||
profile.setData(buffer.toString());
|
||||
}
|
||||
manager.profileCollect(profile);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -501,7 +501,7 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
|
||||
active = false;
|
||||
manager.collectMetricReadOnly((System.nanoTime() - startNanos) / 1000L);
|
||||
if (profileStream != null) {
|
||||
profileStream.end(manager, null);
|
||||
profileStream.end(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -856,7 +856,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
}
|
||||
manager.collectMetric(exeMicros);
|
||||
if (profileStream != null) {
|
||||
profileStream.end(manager, label);
|
||||
profileStream.end(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-6
@@ -9,13 +9,9 @@ import org.jspecify.annotations.Nullable;
|
||||
*/
|
||||
public final class NoopProfileHandler implements SpiProfileHandler {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public void collectTransactionProfile(TransactionProfile transactionProfile) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileStream createProfileStream(@Nullable ProfileLocation location, String label) {
|
||||
public ProfileStream createProfileStream(@Nullable ProfileLocation location, @Nullable String label) {
|
||||
// always return null
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public interface ProfileStream {
|
||||
/**
|
||||
* Add a query event.
|
||||
*/
|
||||
void addQueryEvent(String event, long offset, String beanName, int beanCount, String queryId, String sql);
|
||||
void addQueryEvent(String event, long offset, String beanName, int beanCount, String queryId, String hash, String sql);
|
||||
|
||||
/**
|
||||
* Add a persist event.
|
||||
@@ -28,5 +28,5 @@ public interface ProfileStream {
|
||||
/**
|
||||
* Transaction completed collect the profiling information.
|
||||
*/
|
||||
void end(TransactionManager manager, String label);
|
||||
void end(String label);
|
||||
}
|
||||
|
||||
@@ -428,13 +428,6 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
cacheNotify.notify(new ServerCacheNotification(touchedTables));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the collected transaction profiling information.
|
||||
*/
|
||||
final void profileCollect(TransactionProfile transactionProfile) {
|
||||
profileHandler.collectTransactionProfile(transactionProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect execution time for an explicit transaction.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package io.ebeaninternal.server.persist;
|
||||
|
||||
import io.ebeaninternal.api.SpiProfileTransactionEvent;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class BatchedPstmtTest {
|
||||
|
||||
@Test
|
||||
void executeBatch_profilesBeforeClearingBatch() throws SQLException {
|
||||
var pstmt = mock(PreparedStatement.class);
|
||||
var transaction = mock(SpiTransaction.class);
|
||||
var postExecute = mock(BatchPostExecute.class);
|
||||
|
||||
when(pstmt.executeBatch()).thenReturn(new int[]{1});
|
||||
when(transaction.profileOffset()).thenReturn(42L);
|
||||
doAnswer(invocation -> {
|
||||
var event = invocation.getArgument(0, SpiProfileTransactionEvent.class);
|
||||
event.profile();
|
||||
return null;
|
||||
}).when(transaction).profileEvent(any());
|
||||
|
||||
var batched = new BatchedPstmt(pstmt, false, "insert into foo values (?)", transaction);
|
||||
batched.add(postExecute);
|
||||
|
||||
batched.executeBatch(false);
|
||||
|
||||
verify(postExecute).checkRowCount(1);
|
||||
verify(postExecute).postExecute();
|
||||
verify(postExecute).addTimingBatch(anyLong(), eq(1));
|
||||
verify(postExecute).profile(42L, 1);
|
||||
assertThat(batched.isEmpty()).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -44,4 +44,50 @@ class DQueryPlanMetricTest {
|
||||
assertThat(result.get(0).total()).isEqualTo(410);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void visitCumulativeResetsMax() {
|
||||
|
||||
DQueryPlanMeta meta = new DQueryPlanMeta(Object.class, "lab", null, "sql");
|
||||
DTimedMetric metric = new DTimedMetric("org.timed.plan");
|
||||
DQueryPlanMetric planMetric = new DQueryPlanMetric(meta, metric);
|
||||
|
||||
metric.add(560);
|
||||
metric.add(260);
|
||||
{
|
||||
BasicMetricVisitor visitor = new BasicMetricVisitor("v", naming, false, true, true, true);
|
||||
planMetric.visit(visitor);
|
||||
List<MetaQueryMetric> result = visitor.queryMetrics();
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).name()).isEqualTo("prefix[dto-Object_lab]");
|
||||
assertThat(result.get(0).count()).isEqualTo(2);
|
||||
assertThat(result.get(0).total()).isEqualTo(820);
|
||||
assertThat(result.get(0).max()).isEqualTo(560);
|
||||
}
|
||||
{
|
||||
BasicMetricVisitor visitor = new BasicMetricVisitor("v", naming, false, true, true, true);
|
||||
planMetric.visit(visitor);
|
||||
List<MetaQueryMetric> result = visitor.queryMetrics();
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).name()).isEqualTo("prefix[dto-Object_lab]");
|
||||
assertThat(result.get(0).count()).isEqualTo(2);
|
||||
assertThat(result.get(0).total()).isEqualTo(820);
|
||||
assertThat(result.get(0).max()).isEqualTo(0);
|
||||
}
|
||||
|
||||
metric.add(410);
|
||||
{
|
||||
BasicMetricVisitor visitor = new BasicMetricVisitor("v", naming, false, true, true, true);
|
||||
planMetric.visit(visitor);
|
||||
List<MetaQueryMetric> result = visitor.queryMetrics();
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).name()).isEqualTo("prefix[dto-Object_lab]");
|
||||
assertThat(result.get(0).count()).isEqualTo(3);
|
||||
assertThat(result.get(0).total()).isEqualTo(1230);
|
||||
assertThat(result.get(0).max()).isEqualTo(410);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,4 +90,30 @@ public class DTimedMetricTest {
|
||||
assertThat(result.get(0).total()).isEqualTo(410);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectCumulativeResetsMax() {
|
||||
DTimedMetric metric = new DTimedMetric("org.timed");
|
||||
metric.add(560);
|
||||
metric.add(500);
|
||||
|
||||
DTimeMetricStats stats = metric.collect(false);
|
||||
assertThat(stats.count()).isEqualTo(2);
|
||||
assertThat(stats.total()).isEqualTo(1060);
|
||||
assertThat(stats.max()).isEqualTo(560);
|
||||
|
||||
stats = metric.collect(false);
|
||||
assertThat(stats.count()).isEqualTo(2);
|
||||
assertThat(stats.total()).isEqualTo(1060);
|
||||
assertThat(stats.max()).isEqualTo(0);
|
||||
|
||||
metric.add(160);
|
||||
metric.add(100);
|
||||
metric.add(150);
|
||||
|
||||
stats = metric.collect(false);
|
||||
assertThat(stats.count()).isEqualTo(5);
|
||||
assertThat(stats.total()).isEqualTo(1470);
|
||||
assertThat(stats.max()).isEqualTo(160);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean ddl generation</name>
|
||||
@@ -28,14 +28,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-all</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+19
-23
@@ -1,9 +1,7 @@
|
||||
package io.ebeaninternal.dbmigration.model.build;
|
||||
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.platform.h2.H2Platform;
|
||||
import io.ebean.platform.sqlserver.SqlServer17Platform;
|
||||
@@ -57,27 +55,25 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
|
||||
|
||||
ModelContainer model = new ModelContainer();
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName("h2");
|
||||
config.loadFromProperties();
|
||||
config.setName("h2other");
|
||||
config.setAllQuotedIdentifiers(true);
|
||||
config.setDdlGenerate(false);
|
||||
config.setDdlRun(false);
|
||||
config.setDdlExtra(false);
|
||||
config.setDefaultServer(false);
|
||||
config.setRegister(false);
|
||||
|
||||
config.addClass(CKeyDetail.class);
|
||||
config.addClass(CKeyParent.class);
|
||||
config.addClass(CKeyAssoc.class);
|
||||
config.addClass(CKeyParentId.class);
|
||||
config.setDbOffline(true);
|
||||
config.setDatabasePlatform(new SqlServer17Platform());
|
||||
|
||||
final SpiEbeanServer database = (SpiEbeanServer) DatabaseFactory.create(config);
|
||||
final SpiEbeanServer database = (SpiEbeanServer) Database.builder()
|
||||
.name("h2")
|
||||
.loadFromProperties()
|
||||
.name("h2other")
|
||||
.allQuotedIdentifiers(true)
|
||||
.ddlGenerate(false)
|
||||
.ddlRun(false)
|
||||
.ddlExtra(false)
|
||||
.defaultDatabase(false)
|
||||
.register(false)
|
||||
.addClass(CKeyDetail.class)
|
||||
.addClass(CKeyParent.class)
|
||||
.addClass(CKeyAssoc.class)
|
||||
.addClass(CKeyParentId.class)
|
||||
.offline(true)
|
||||
.databasePlatform(new SqlServer17Platform())
|
||||
.build();
|
||||
try {
|
||||
ModelBuildContext ctx = new ModelBuildContext(model, config.getDatabasePlatform(), config.getConstraintNaming(), true);
|
||||
ModelBuildContext ctx = new ModelBuildContext(model, database.config().getDatabasePlatform(), database.config().getConstraintNaming(), true);
|
||||
|
||||
ModelBuildBeanVisitor addTable = new ModelBuildBeanVisitor(ctx);
|
||||
|
||||
|
||||
+15
-21
@@ -1,10 +1,7 @@
|
||||
package io.ebeaninternal.dbmigration.model.build;
|
||||
|
||||
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.Database;
|
||||
import io.localtest.BaseTestCase;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.Helper;
|
||||
import io.ebeaninternal.dbmigration.migration.Migration;
|
||||
@@ -25,23 +22,20 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class ModelBuild_compoundKeyTest extends BaseTestCase {
|
||||
|
||||
private SpiEbeanServer createServer() {
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
config.setName("h2");
|
||||
config.loadFromProperties();
|
||||
config.setName("h2other");
|
||||
config.setDdlGenerate(false);
|
||||
config.setDdlRun(false);
|
||||
config.setDdlExtra(false);
|
||||
config.setDefaultServer(false);
|
||||
config.setRegister(false);
|
||||
|
||||
config.addClass(CKeyDetail.class);
|
||||
config.addClass(CKeyParent.class);
|
||||
config.addClass(CKeyAssoc.class);
|
||||
config.addClass(CKeyParentId.class);
|
||||
|
||||
return (SpiEbeanServer) DatabaseFactory.create(config);
|
||||
return (SpiEbeanServer) Database.builder()
|
||||
.name("h2")
|
||||
.loadFromProperties()
|
||||
.name("h2other")
|
||||
.ddlGenerate(false)
|
||||
.ddlRun(false)
|
||||
.ddlExtra(false)
|
||||
.defaultDatabase(false)
|
||||
.register(false)
|
||||
.addClass(CKeyDetail.class)
|
||||
.addClass(CKeyParent.class)
|
||||
.addClass(CKeyAssoc.class)
|
||||
.addClass(CKeyParentId.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+13
-16
@@ -1,10 +1,7 @@
|
||||
package io.ebeaninternal.dbmigration.model.build;
|
||||
|
||||
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.Database;
|
||||
import io.localtest.BaseTestCase;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.Helper;
|
||||
import io.ebeaninternal.dbmigration.model.CurrentModel;
|
||||
@@ -21,18 +18,18 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class ModelBuild_compound_IdClassTest extends BaseTestCase {
|
||||
|
||||
private SpiEbeanServer createServer() {
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
config.setName("h2");
|
||||
config.loadFromProperties();
|
||||
config.setName("h2other");
|
||||
config.setDdlGenerate(false);
|
||||
config.setDdlRun(false);
|
||||
config.setDdlExtra(false);
|
||||
config.setDefaultServer(false);
|
||||
config.setRegister(false);
|
||||
config.addClass(CKSiteUser.class);
|
||||
config.addClass(CKEmbId.class);
|
||||
return (SpiEbeanServer) DatabaseFactory.create(config);
|
||||
return (SpiEbeanServer) Database.builder()
|
||||
.name("h2")
|
||||
.loadFromProperties()
|
||||
.name("h2other")
|
||||
.ddlGenerate(false)
|
||||
.ddlRun(false)
|
||||
.ddlExtra(false)
|
||||
.defaultDatabase(false)
|
||||
.register(false)
|
||||
.addClass(CKSiteUser.class)
|
||||
.addClass(CKEmbId.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+14
-20
@@ -1,9 +1,6 @@
|
||||
package io.ebeaninternal.dbmigration.model.build;
|
||||
|
||||
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.Database;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.Helper;
|
||||
@@ -20,22 +17,19 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class ModelBuild_explicitSequencesTest extends BaseTestCase {
|
||||
|
||||
private SpiEbeanServer createServer(boolean postgres) {
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
config.setName("h2");
|
||||
config.loadFromProperties();
|
||||
config.setName("h2other");
|
||||
config.setDdlGenerate(false);
|
||||
config.setDdlRun(false);
|
||||
config.setDdlExtra(false);
|
||||
config.setDefaultServer(false);
|
||||
config.setRegister(false);
|
||||
|
||||
config.setDatabasePlatformName(postgres ? "postgres" : "h2");
|
||||
|
||||
config.addClass(Person.class);
|
||||
config.addClass(Phone.class);
|
||||
return (SpiEbeanServer) DatabaseFactory.create(config);
|
||||
return (SpiEbeanServer) Database.builder()
|
||||
.name("h2")
|
||||
.loadFromProperties()
|
||||
.name("h2other")
|
||||
.ddlGenerate(false)
|
||||
.ddlRun(false)
|
||||
.ddlExtra(false)
|
||||
.defaultDatabase(false)
|
||||
.register(false)
|
||||
.databasePlatformName(postgres ? "postgres" : "h2")
|
||||
.addClass(Person.class)
|
||||
.addClass(Phone.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean net postgis types</name>
|
||||
@@ -19,14 +19,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope -->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-opentelemetry</artifactId>
|
||||
@@ -12,7 +12,7 @@
|
||||
<description>Ebean OpenTelemetry integration - transaction and query tracing via SpiProfileHandler</description>
|
||||
|
||||
<properties>
|
||||
<opentelemetry.version>1.51.0</opentelemetry.version>
|
||||
<opentelemetry.version>1.62.0</opentelemetry.version>
|
||||
<surefire.useModulePath>false</surefire.useModulePath>
|
||||
</properties>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -71,21 +71,21 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import io.ebean.plugin.Plugin;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebeaninternal.api.SpiProfileHandler;
|
||||
import io.ebeaninternal.server.transaction.ProfileStream;
|
||||
import io.ebeaninternal.server.transaction.TransactionProfile;
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
@@ -39,8 +38,8 @@ public final class OtelProfileHandler implements SpiProfileHandler, Plugin {
|
||||
|
||||
@Override
|
||||
public void configure(SpiServer server) {
|
||||
if (this.tracer == null) {
|
||||
this.tracer = GlobalOpenTelemetry.getTracer(INSTRUMENTATION_NAME);
|
||||
if (tracer == null) {
|
||||
tracer = GlobalOpenTelemetry.getTracer(INSTRUMENTATION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +63,7 @@ public final class OtelProfileHandler implements SpiProfileHandler, Plugin {
|
||||
*/
|
||||
@Override
|
||||
public @Nullable ProfileStream createProfileStream(@Nullable ProfileLocation location, @Nullable String label) {
|
||||
if (!Span.current().getSpanContext().isValid()) {
|
||||
if (!Span.current().isRecording()) {
|
||||
// No active OTel trace context — don't create spans to avoid noise
|
||||
return null;
|
||||
}
|
||||
@@ -79,11 +78,4 @@ public final class OtelProfileHandler implements SpiProfileHandler, Plugin {
|
||||
return new OtelProfileStream(tracer, txnSpan);
|
||||
}
|
||||
|
||||
/**
|
||||
* The stream handles span lifecycle inline — nothing to do here.
|
||||
*/
|
||||
@Override
|
||||
public void collectTransactionProfile(TransactionProfile transactionProfile) {
|
||||
// no-op: OtelProfileStream.end() already closed the span
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ final class OtelProfileStream implements ProfileStream {
|
||||
static final AttributeKey<String> DB_QUERY_TEXT = AttributeKey.stringKey("db.query.text");
|
||||
static final AttributeKey<Long> DB_QUERY_TIME = AttributeKey.longKey("db.query.time");
|
||||
static final AttributeKey<String> EBEAN_BEAN_TYPE = AttributeKey.stringKey("ebean.bean_type");
|
||||
static final AttributeKey<String> EBEAN_QUERY_HASH = AttributeKey.stringKey("ebean.query_hash");
|
||||
static final AttributeKey<Long> EBEAN_ROW_COUNT = AttributeKey.longKey("ebean.row_count");
|
||||
static final AttributeKey<Long> EBEAN_TOTAL_MICROS = AttributeKey.longKey("ebean.total_micros");
|
||||
|
||||
@@ -45,18 +46,21 @@ final class OtelProfileStream implements ProfileStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addQueryEvent(String event, long offset, String beanName, int beanCount, String queryId, String sql) {
|
||||
public void addQueryEvent(String event, long offset, String beanName, int beanCount, String queryId, String hash, String sql) {
|
||||
long exeMicros = offset() - offset;
|
||||
var now = Instant.now();
|
||||
String operation = operationName(event);
|
||||
String name = queryId != null ? queryId : operation + " " + beanName;
|
||||
Span child = childSpanBuilder(name, now.minus(exeMicros, ChronoUnit.MICROS))
|
||||
SpanBuilder builder = childSpanBuilder(name, now.minus(exeMicros, ChronoUnit.MICROS))
|
||||
.setAttribute(DB_OPERATION, operation)
|
||||
.setAttribute(EBEAN_BEAN_TYPE, beanName)
|
||||
.setAttribute(EBEAN_ROW_COUNT, (long) beanCount)
|
||||
.setAttribute(DB_QUERY_TEXT, sql)
|
||||
.setAttribute(DB_QUERY_TIME, exeMicros)
|
||||
.startSpan();
|
||||
.setAttribute(DB_QUERY_TIME, exeMicros);
|
||||
if (hash != null) {
|
||||
builder.setAttribute(EBEAN_QUERY_HASH, hash);
|
||||
}
|
||||
Span child = builder.startSpan();
|
||||
child.end(now);
|
||||
}
|
||||
|
||||
@@ -84,7 +88,7 @@ final class OtelProfileStream implements ProfileStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(TransactionManager manager, String label) {
|
||||
public void end(String label) {
|
||||
txnSpan.setAttribute(EBEAN_TOTAL_MICROS, offset());
|
||||
if (label != null) {
|
||||
txnSpan.updateName("txn." + label);
|
||||
|
||||
+18
-15
@@ -85,7 +85,7 @@ class OtelProfileHandlerTest {
|
||||
var stream = handler.createProfileStream(null, null);
|
||||
assertNotNull(stream);
|
||||
stream.addEvent("c", 0); // commit
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
@@ -98,7 +98,7 @@ class OtelProfileHandlerTest {
|
||||
var stream = handler.createProfileStream(mockLocation("OrderService.placeOrder"), null);
|
||||
assertNotNull(stream);
|
||||
stream.addEvent("c", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
@@ -119,9 +119,9 @@ class OtelProfileHandlerTest {
|
||||
OtelProfileStream stream = (OtelProfileStream) handler.createProfileStream(null, null);
|
||||
assertNotNull(stream);
|
||||
// First query event should update the transaction span name
|
||||
stream.addQueryEvent("fm", stream.offset(), "Customer", 5, "qplan-1", "select ...");
|
||||
stream.addQueryEvent("fm", stream.offset(), "Customer", 5, "qplan-1", "h1", "select ...");
|
||||
stream.addEvent("c", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
@@ -141,9 +141,9 @@ class OtelProfileHandlerTest {
|
||||
assertNotNull(stream);
|
||||
long offset = stream.offset();
|
||||
// Simulate some time passing then record a find_many
|
||||
stream.addQueryEvent("fm", offset, "Order", 42, "plan-abc", "select ...");
|
||||
stream.addQueryEvent("fm", offset, "Order", 42, "plan-abc", "abc123hash", "select ...");
|
||||
stream.addEvent("c", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
@@ -155,6 +155,7 @@ class OtelProfileHandlerTest {
|
||||
assertEquals("Order", querySpan.getAttributes().get(OtelProfileStream.EBEAN_BEAN_TYPE));
|
||||
assertEquals(42L, querySpan.getAttributes().get(OtelProfileStream.EBEAN_ROW_COUNT));
|
||||
assertEquals("select ...", querySpan.getAttributes().get(OtelProfileStream.DB_QUERY_TEXT));
|
||||
assertEquals("abc123hash", querySpan.getAttributes().get(OtelProfileStream.EBEAN_QUERY_HASH));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -163,10 +164,10 @@ class OtelProfileHandlerTest {
|
||||
try (Scope ignored = parent.makeCurrent()) {
|
||||
OtelProfileStream stream = (OtelProfileStream) handler.createProfileStream(mockLocation("MyService.doAll"), null);
|
||||
assertNotNull(stream);
|
||||
stream.addQueryEvent("fo", stream.offset(), "User", 1, "p1", "select from user");
|
||||
stream.addQueryEvent("fm", stream.offset(), "Order", 10, "p2", "select from order");
|
||||
stream.addQueryEvent("fo", stream.offset(), "User", 1, "p1", "h1", "select from user");
|
||||
stream.addQueryEvent("fm", stream.offset(), "Order", 10, "p2", "h2", "select from order");
|
||||
stream.addEvent("c", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
@@ -184,15 +185,17 @@ class OtelProfileHandlerTest {
|
||||
try (Scope ignored = parent.makeCurrent()) {
|
||||
OtelProfileStream stream = (OtelProfileStream) handler.createProfileStream(mockLocation("MyService.emptySql"), null);
|
||||
assertNotNull(stream);
|
||||
stream.addQueryEvent("fo", stream.offset(), "User", 1, "p1", "");
|
||||
stream.addQueryEvent("fo", stream.offset(), "User", 1, "p1", null, "");
|
||||
stream.addEvent("c", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
SpanData querySpan = findSpan("p1");
|
||||
assertNotNull(querySpan);
|
||||
assertEquals("", querySpan.getAttributes().get(OtelProfileStream.DB_QUERY_TEXT));
|
||||
// null hash should not set the attribute
|
||||
assertNull(querySpan.getAttributes().get(OtelProfileStream.EBEAN_QUERY_HASH));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
@@ -208,7 +211,7 @@ class OtelProfileHandlerTest {
|
||||
long offset = stream.offset();
|
||||
stream.addPersistEvent("i", offset, "Order", 1);
|
||||
stream.addEvent("c", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
@@ -230,7 +233,7 @@ class OtelProfileHandlerTest {
|
||||
OtelProfileStream stream = (OtelProfileStream) handler.createProfileStream(mockLocation("Svc.ok"), null);
|
||||
assertNotNull(stream);
|
||||
stream.addEvent("c", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
@@ -246,7 +249,7 @@ class OtelProfileHandlerTest {
|
||||
OtelProfileStream stream = (OtelProfileStream) handler.createProfileStream(mockLocation("Svc.fail"), null);
|
||||
assertNotNull(stream);
|
||||
stream.addEvent("r", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
@@ -266,7 +269,7 @@ class OtelProfileHandlerTest {
|
||||
OtelProfileStream stream = (OtelProfileStream) handler.createProfileStream(mockLocation("Svc.timed"), null);
|
||||
assertNotNull(stream);
|
||||
stream.addEvent("c", 0);
|
||||
stream.end(null, null);
|
||||
stream.end(null);
|
||||
} finally {
|
||||
parent.end();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.example.domain;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.config.ProfilingConfig;
|
||||
import io.ebean.datasource.DataSourceBuilder;
|
||||
import io.ebean.datasource.DataSourcePool;
|
||||
import io.ebean.opentelemetry.OtelProfileHandler;
|
||||
@@ -123,9 +122,6 @@ class OtelJaegerIntegrationTest {
|
||||
}
|
||||
|
||||
private Database createDatabase(Tracer tracer) {
|
||||
ProfilingConfig profilingConfig = new ProfilingConfig();
|
||||
profilingConfig.setEnabled(true);
|
||||
|
||||
DataSourcePool ds = DataSourceBuilder.create()
|
||||
.url("jdbc:h2:mem:otelit;DB_CLOSE_DELAY=-1")
|
||||
.username("sa")
|
||||
@@ -140,7 +136,6 @@ class OtelJaegerIntegrationTest {
|
||||
.loadFromProperties()
|
||||
.ddlGenerate(true)
|
||||
.ddlRun(true)
|
||||
.profilingConfig(profilingConfig)
|
||||
.putServiceObject(SpiProfileHandler.class, new OtelProfileHandler(tracer))
|
||||
.addClass(OtelOrder.class)
|
||||
.dataSource(ds)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean pgvector types</name>
|
||||
@@ -19,14 +19,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope -->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean postgis types</name>
|
||||
@@ -19,14 +19,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope -->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean querybean</name>
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -59,14 +59,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -26,6 +26,35 @@ public final class PString<R> extends PBaseComparable<R, String> {
|
||||
super(name, root, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is equal to if the value is non-null and not blank, otherwise no expression is added to the query.
|
||||
* <p>
|
||||
* This is like {@code eqIfPresent()} but additionally treats an empty or whitespace-only value as
|
||||
* "not present". When present, the value is trimmed before being used in the equal to expression.
|
||||
* <p>
|
||||
* This is a helper for building queries in fluid style where a String predicate is effectively
|
||||
* optional, avoiding a separate {@code if} block and {@code trimToNull()} style helper.
|
||||
*
|
||||
* <pre>{@code
|
||||
* List<Customer> customers = new QCustomer()
|
||||
* .name.eqIfNotBlank(nameFilter)
|
||||
* .status.eqIfPresent(statusFilter)
|
||||
* .findList();
|
||||
* }</pre>
|
||||
*
|
||||
* @param value the value which can be null or blank
|
||||
* @return the root query bean instance
|
||||
*/
|
||||
public R eqIfNotBlank(@Nullable String value) {
|
||||
if (value != null) {
|
||||
String trimmed = value.trim();
|
||||
if (!trimmed.isEmpty()) {
|
||||
expr().eq(_name, trimmed);
|
||||
}
|
||||
}
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive is equal to.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.querytest;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import org.example.domain.Customer;
|
||||
import org.example.domain.query.QCustomer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.example.domain.query.QCustomer.Alias.name;
|
||||
|
||||
class QStringEqIfNotBlankTest {
|
||||
|
||||
@Test
|
||||
void present_addsEqPredicate() {
|
||||
var q = new QCustomer()
|
||||
.select(name)
|
||||
.name.eqIfNotBlank("rob")
|
||||
.query();
|
||||
|
||||
q.findList();
|
||||
assertThat(q.getGeneratedSql()).contains("where t0.name = ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
void null_skipsPredicate() {
|
||||
var q = new QCustomer()
|
||||
.select(name)
|
||||
.name.isNotNull()
|
||||
.name.eqIfNotBlank(null)
|
||||
.query();
|
||||
|
||||
q.findList();
|
||||
assertThat(q.getGeneratedSql()).doesNotContain("t0.name = ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
void blankWhitespace_skipsPredicate() {
|
||||
var q = new QCustomer()
|
||||
.select(name)
|
||||
.name.isNotNull()
|
||||
.name.eqIfNotBlank(" ")
|
||||
.query();
|
||||
|
||||
q.findList();
|
||||
assertThat(q.getGeneratedSql()).doesNotContain("t0.name = ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
void empty_skipsPredicate() {
|
||||
var q = new QCustomer()
|
||||
.select(name)
|
||||
.name.isNotNull()
|
||||
.name.eqIfNotBlank("")
|
||||
.query();
|
||||
|
||||
q.findList();
|
||||
assertThat(q.getGeneratedSql()).doesNotContain("t0.name = ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
void present_trimsBoundValue() {
|
||||
Database db = DB.getDefault();
|
||||
String unique = "eqIfNotBlank-" + System.nanoTime();
|
||||
|
||||
Customer customer = new Customer();
|
||||
customer.name = unique;
|
||||
db.save(customer);
|
||||
|
||||
Customer found = new QCustomer(db)
|
||||
.name.eqIfNotBlank(" " + unique + " ")
|
||||
.findOne();
|
||||
|
||||
assertThat(found).isNotNull();
|
||||
assertThat(found.name).isEqualTo(unique);
|
||||
|
||||
db.delete(customer);
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ class QueryAlsoIfTest {
|
||||
.query();
|
||||
|
||||
q.findList();
|
||||
assertThat(q.getGeneratedSql()).isEqualTo("select /* QueryAlsoIfTest.also */ t0.id, t0.name from be_customer t0 where t0.name is not null and t0.email is not null");
|
||||
assertThat(q.getGeneratedSql()).contains("from be_customer t0 where t0.name is not null and t0.email is not null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -61,7 +61,7 @@ class QueryAlsoIfTest {
|
||||
.query();
|
||||
|
||||
q.findList();
|
||||
assertThat(q.getGeneratedSql()).isEqualTo("select /* QueryAlsoIfTest.applyIfPresent */ t0.id, t0.name from be_customer t0 where t0.name is not null and t0.status = ?");
|
||||
assertThat(q.getGeneratedSql()).contains("from be_customer t0 where t0.name is not null and t0.status = ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -74,7 +74,7 @@ class QueryAlsoIfTest {
|
||||
.query();
|
||||
|
||||
q.findList();
|
||||
assertThat(q.getGeneratedSql()).isEqualTo("select /* QueryAlsoIfTest.notApplyIfPresent */ t0.id, t0.name from be_customer t0 where t0.name is not null");
|
||||
assertThat(q.getGeneratedSql()).contains("from be_customer t0 where t0.name is not null");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+6
-6
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
@@ -29,35 +29,35 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@ to integrate with Springs JDBC Transaction manager.
|
||||
## To use
|
||||
|
||||
```java
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
|
||||
// set SpringJdbcTransactionManager ... as the external transaction manager
|
||||
config.setExternalTransactionManager(new SpringJdbcTransactionManager());
|
||||
|
||||
...
|
||||
Database database = DatabaseFactory.create(config);
|
||||
Database database = config.build();
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-spring-txn</artifactId>
|
||||
@@ -28,7 +28,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.example;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
@@ -33,7 +32,7 @@ public class EbeanServerFactoryBean implements InitializingBean, FactoryBean<Dat
|
||||
|
||||
serverConfig.setPersistBatch(PersistBatch.ALL);
|
||||
// Create the new EbeanServer using the configuration
|
||||
this.ebeanServer = DatabaseFactory.create(serverConfig);
|
||||
this.ebeanServer = serverConfig.build();
|
||||
}
|
||||
|
||||
public Database getObject() throws Exception {
|
||||
|
||||
+6
-6
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean test</name>
|
||||
@@ -33,20 +33,20 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-h2</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -149,14 +149,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jackson-mapper</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-all</artifactId>
|
||||
<version>16.6.0</version>
|
||||
<version>16.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebean.test.config.platform;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.datasource.DataSourceBuilder;
|
||||
import io.ebeaninternal.api.DbOffline;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
@@ -29,7 +29,7 @@ class ConfigTest {
|
||||
|
||||
@Test
|
||||
void trimExtensions() {
|
||||
Config config = new Config("db", "db", "db", new DatabaseConfig());
|
||||
Config config = new Config("db", "db", "db", Database.builder().settings());
|
||||
|
||||
assertThat(config.trimExtensions("a,b")).isEqualTo("a,b");
|
||||
assertThat(config.trimExtensions(" a , b ")).isEqualTo("a,b");
|
||||
@@ -38,10 +38,10 @@ class ConfigTest {
|
||||
|
||||
@Test
|
||||
void extensions_whenNoSetValues() {
|
||||
DatabaseConfig databaseBuilder = new DatabaseConfig();
|
||||
DatabaseBuilder databaseBuilder = Database.builder();
|
||||
databaseBuilder.loadFromProperties(new Properties());
|
||||
|
||||
Config config = new Config("db", "postgis", "db", databaseBuilder);
|
||||
Config config = new Config("db", "postgis", "db", databaseBuilder.settings());
|
||||
|
||||
config.setUsernameDefault();
|
||||
config.setPasswordDefault();
|
||||
@@ -56,13 +56,13 @@ class ConfigTest {
|
||||
|
||||
@Test
|
||||
void extensions_whenSetValues() {
|
||||
DatabaseConfig databaseBuilder = new DatabaseConfig();
|
||||
DatabaseBuilder databaseBuilder = Database.builder();
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("ebean.test.extensions", "x,y");
|
||||
properties.setProperty("ebean.test.extraDb.extensions", "z");
|
||||
databaseBuilder.loadFromProperties(properties);
|
||||
|
||||
Config config = new Config("db", "postgis", "db", databaseBuilder);
|
||||
Config config = new Config("db", "postgis", "db", databaseBuilder.settings());
|
||||
|
||||
config.setExtensions("a,b");
|
||||
config.setExtraExtensions("c,d");
|
||||
@@ -78,7 +78,7 @@ class ConfigTest {
|
||||
Properties p = new Properties();
|
||||
p.setProperty("ebean.test.extraDb", "other");
|
||||
|
||||
DatabaseConfig serverConfig = new DatabaseConfig();
|
||||
DatabaseBuilder.Settings serverConfig = Database.builder().settings();
|
||||
serverConfig.loadFromProperties(p);
|
||||
|
||||
Config config = new Config("other", "postgres", "other", serverConfig);
|
||||
@@ -100,7 +100,7 @@ class ConfigTest {
|
||||
Properties p = new Properties();
|
||||
p.setProperty("ebean.test.extraDb.dbName", "other");
|
||||
|
||||
DatabaseConfig serverConfig = new DatabaseConfig();
|
||||
DatabaseBuilder.Settings serverConfig = Database.builder().settings();
|
||||
serverConfig.loadFromProperties(p);
|
||||
|
||||
Config config = new Config("other", "postgres", "other", serverConfig);
|
||||
@@ -126,7 +126,7 @@ class ConfigTest {
|
||||
p.setProperty("ebean.test.extraDb.password", "other_pwd");
|
||||
p.setProperty("ebean.test.extraDb.url", "other_url");
|
||||
|
||||
DatabaseConfig serverConfig = new DatabaseConfig();
|
||||
DatabaseBuilder.Settings serverConfig = Database.builder().settings();
|
||||
serverConfig.setName("scOther");
|
||||
serverConfig.loadFromProperties(p);
|
||||
|
||||
@@ -151,7 +151,7 @@ class ConfigTest {
|
||||
sourceProperties.setProperty("ebean.test.dbName", "main");
|
||||
sourceProperties.setProperty("ebean.test.extraDb.dbName", "central");
|
||||
|
||||
DatabaseConfig serverConfig = new DatabaseConfig();
|
||||
DatabaseBuilder.Settings serverConfig = Database.builder().settings();
|
||||
serverConfig.setName("main");
|
||||
serverConfig.loadFromProperties(sourceProperties);
|
||||
|
||||
@@ -164,8 +164,8 @@ class ConfigTest {
|
||||
assertThat(mainProps.getProperty("datasource.main.username")).isEqualTo("main");
|
||||
|
||||
|
||||
DatabaseBuilder centralConfig = new DatabaseConfig();
|
||||
centralConfig.setName("central");
|
||||
DatabaseBuilder centralConfig = Database.builder().settings();
|
||||
centralConfig.name("central");
|
||||
centralConfig.loadFromProperties(sourceProperties);
|
||||
|
||||
Config extraConfig = new Config("central", "postgres", "central", serverConfig);
|
||||
@@ -220,10 +220,10 @@ class ConfigTest {
|
||||
}
|
||||
|
||||
private Config createConfig(Properties p) {
|
||||
DatabaseConfig serverConfig = new DatabaseConfig();
|
||||
serverConfig.setName("scOther");
|
||||
DatabaseBuilder serverConfig = Database.builder();
|
||||
serverConfig.name("scOther");
|
||||
serverConfig.loadFromProperties(p);
|
||||
return new Config("db_name", "postgres", "db_name", serverConfig);
|
||||
return new Config("db_name", "postgres", "db_name", serverConfig.settings());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-7
@@ -3,7 +3,6 @@ package io.ebean.xtest.base;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.config.*;
|
||||
import io.ebean.platform.mysql.MySqlPlatform;
|
||||
import io.ebean.platform.postgres.PostgresPlatform;
|
||||
@@ -28,7 +27,7 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase {
|
||||
TenantDataSourceProvider dataSourceProvider = Mockito.mock(TenantDataSourceProvider.class);
|
||||
Mockito.doReturn(mockedDataSource).when(dataSourceProvider).dataSource(tenant);
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("multiTenantDb");
|
||||
config.loadFromProperties();
|
||||
config.setRegister(false);
|
||||
@@ -44,7 +43,7 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase {
|
||||
//config.setDdlRun(false);
|
||||
config.setDatabasePlatform(new PostgresPlatform());
|
||||
|
||||
final Database database = DatabaseFactory.create(config);
|
||||
final Database database = config.build();
|
||||
database.shutdown();
|
||||
}
|
||||
|
||||
@@ -63,7 +62,7 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase {
|
||||
TenantSchemaProvider schemaProvider = Mockito.mock(TenantSchemaProvider.class);
|
||||
Mockito.doReturn("tenant_schema").when(schemaProvider).schema(tenant);
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("h2");
|
||||
config.loadFromProperties();
|
||||
config.setName("multi-tenancy");
|
||||
@@ -77,7 +76,7 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase {
|
||||
config.setDdlRun(false);
|
||||
config.setDatabasePlatform(new MySqlPlatform());
|
||||
|
||||
final Database database = DatabaseFactory.create(config);
|
||||
final Database database = config.build();
|
||||
database.shutdown();
|
||||
}
|
||||
|
||||
@@ -94,7 +93,7 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase {
|
||||
TenantCatalogProvider catalogProvider = Mockito.mock(TenantCatalogProvider.class);
|
||||
Mockito.doReturn("tenant_catalog").when(catalogProvider).catalog(tenant);
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("h2");
|
||||
config.loadFromProperties();
|
||||
config.setName("multi-tenancy");
|
||||
@@ -108,7 +107,7 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase {
|
||||
config.setDdlRun(false);
|
||||
config.setDatabasePlatform(new MySqlPlatform());
|
||||
|
||||
final Database database = DatabaseFactory.create(config);
|
||||
final Database database = config.build();
|
||||
database.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -1,9 +1,7 @@
|
||||
package io.ebean.xtest.base;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.event.ServerConfigStartup;
|
||||
import io.ebeaninternal.api.SpiLogger;
|
||||
import io.ebeaninternal.api.SpiLoggerFactory;
|
||||
@@ -46,7 +44,7 @@ public class EbeanServerFactory_ServerConfigStart_Test {
|
||||
@Test
|
||||
public void test() throws InterruptedException {
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("h2");
|
||||
config.loadFromProperties();
|
||||
config.setName("h2other");
|
||||
@@ -65,7 +63,7 @@ public class EbeanServerFactory_ServerConfigStart_Test {
|
||||
MySpiLoggerFactory loggerFactory = new MySpiLoggerFactory();
|
||||
config.putServiceObject(SpiLoggerFactory.class, loggerFactory);
|
||||
|
||||
Database db = DatabaseFactory.create(config);
|
||||
Database db = config.build();
|
||||
|
||||
assertThat(loggerFactory.loggers).containsExactlyInAnyOrder("io.ebean.SQL", "io.ebean.SUM", "io.ebean.TXN");
|
||||
|
||||
@@ -77,7 +75,7 @@ public class EbeanServerFactory_ServerConfigStart_Test {
|
||||
// test server shutdown and restart using the same DatabaseConfig
|
||||
db.shutdown(true, false);
|
||||
|
||||
Database restartedServer = DatabaseFactory.create(config);
|
||||
Database restartedServer = config.build();
|
||||
restartedServer.shutdown(true, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -437,4 +437,14 @@ public class UpdateQueryTest extends BaseTestCase {
|
||||
|
||||
return b0.getId();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeoutPropagation() {
|
||||
int timeout = 7;
|
||||
|
||||
var updateQuery = DB.update(Customer.class)
|
||||
.setTimeout(timeout);
|
||||
|
||||
assertThat(updateQuery.getTimeout()).isEqualTo(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package io.ebean.xtest.config;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.dbplatform.DbIdentity;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.platform.h2.H2Platform;
|
||||
@@ -89,7 +87,7 @@ public class PlatformNoGeneratedKeysTest {
|
||||
|
||||
private static Database testH2Server() {
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("h2_noGeneratedKeys");
|
||||
|
||||
OtherH2Platform platform = new OtherH2Platform();
|
||||
@@ -101,10 +99,10 @@ public class PlatformNoGeneratedKeysTest {
|
||||
dbIdentity.setSelectLastInsertedIdTemplate("select identity() --{table}");
|
||||
|
||||
config.setDatabasePlatform(platform);
|
||||
config.getDataSourceConfig().setUsername("sa");
|
||||
config.getDataSourceConfig().setPassword("");
|
||||
config.getDataSourceConfig().setUrl("jdbc:h2:mem:withPCQuery;MODE=LEGACY");
|
||||
config.getDataSourceConfig().setDriver("org.h2.Driver");
|
||||
config.settings().getDataSourceConfig().setUsername("sa");
|
||||
config.settings().getDataSourceConfig().setPassword("");
|
||||
config.settings().getDataSourceConfig().setUrl("jdbc:h2:mem:withPCQuery;MODE=LEGACY");
|
||||
config.settings().getDataSourceConfig().setDriver("org.h2.Driver");
|
||||
|
||||
config.setDisableLazyLoading(true);
|
||||
config.setDisableL2Cache(true);
|
||||
@@ -116,7 +114,7 @@ public class PlatformNoGeneratedKeysTest {
|
||||
config.addClass(BasicDraftableBean.class);
|
||||
config.loadFromProperties(); // trigger auto config for H2 1.x
|
||||
|
||||
return DatabaseFactory.create(config);
|
||||
return config.build();
|
||||
}
|
||||
|
||||
public static class OtherH2Platform extends H2Platform {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package io.ebean.xtest.config;
|
||||
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.xtest.ForPlatform;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -27,7 +24,7 @@ public class ServerConfigSqlServerTest {
|
||||
// no explicit databasePlatformName set ..
|
||||
//props.setProperty("ebean.some_sqlserver.databasePlatformName", "sqlserver17");
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("some_sqlserver");
|
||||
config.loadFromProperties(props);
|
||||
|
||||
@@ -39,7 +36,7 @@ public class ServerConfigSqlServerTest {
|
||||
config.setRegister(false);
|
||||
config.addClass(EBasicVer.class);
|
||||
|
||||
Database sqlServer = DatabaseFactory.create(config);
|
||||
Database sqlServer = config.build();
|
||||
|
||||
assertThat(sqlServer).isNotNull();
|
||||
sqlServer.shutdown();
|
||||
@@ -62,7 +59,7 @@ public class ServerConfigSqlServerTest {
|
||||
|
||||
String name = "testsqlserver17";
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName(name);
|
||||
|
||||
Properties props = props(name);
|
||||
@@ -80,7 +77,7 @@ public class ServerConfigSqlServerTest {
|
||||
config.loadFromProperties(props);
|
||||
config.addClass(EBasicVer.class);
|
||||
|
||||
Database sqlServer = DatabaseFactory.create(config);
|
||||
Database sqlServer = config.build();
|
||||
|
||||
assertThat(sqlServer).isNotNull();
|
||||
sqlServer.shutdown();
|
||||
@@ -95,7 +92,7 @@ public class ServerConfigSqlServerTest {
|
||||
Properties props = props(name);
|
||||
//props.setProperty("ebean.testsqlserver16.databasePlatformName", "sqlserver16");
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setDefaultServer(false);
|
||||
config.setRegister(false);
|
||||
config.setDdlGenerate(true);
|
||||
@@ -106,7 +103,7 @@ public class ServerConfigSqlServerTest {
|
||||
config.loadFromProperties(props);
|
||||
config.addClass(EBasicVer.class);
|
||||
|
||||
Database sqlServer = DatabaseFactory.create(config);
|
||||
Database sqlServer = config.build();
|
||||
|
||||
assertThat(sqlServer).isNotNull();
|
||||
sqlServer.shutdown();
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package io.ebean.xtest.dbmigration;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.dbmigration.DbMigration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
@@ -47,7 +45,7 @@ class DbMigrationDropHistoryTest {
|
||||
|
||||
migration.setPathToResources("src/test/resources");
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("migrationtest-history");
|
||||
config.loadFromProperties();
|
||||
config.setRegister(false);
|
||||
@@ -55,7 +53,7 @@ class DbMigrationDropHistoryTest {
|
||||
|
||||
|
||||
config.setPackages(Arrays.asList("misc.migration.history.v1_0"));
|
||||
Database server = DatabaseFactory.create(config);
|
||||
Database server = config.build();
|
||||
migration.setServer(server);
|
||||
|
||||
// First, we clean up the output-directory
|
||||
@@ -71,7 +69,7 @@ class DbMigrationDropHistoryTest {
|
||||
// and now for v1_1
|
||||
config.setPackages(Arrays.asList("misc.migration.history.v1_1"));
|
||||
server.shutdown();
|
||||
server = DatabaseFactory.create(config);
|
||||
server = config.build();
|
||||
migration.setServer(server);
|
||||
assertThat(migration.generateMigration()).isEqualTo("1.1");
|
||||
assertThat(migration.generateMigration()).isNull(); // subsequent call
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package io.ebean.xtest.dbmigration;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.dbmigration.DbMigration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
@@ -89,15 +87,15 @@ public class DbMigrationGenerateTest {
|
||||
migration.addPlatform(Platform.YUGABYTE);
|
||||
|
||||
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("migrationtest");
|
||||
config.loadFromProperties();
|
||||
config.setRegister(false);
|
||||
config.setDefaultServer(false);
|
||||
config.getProperties().put("ebean.hana.generateUniqueDdl", "true"); // need to generate unique statements to prevent them from being filtered out as duplicates by the DdlRunner
|
||||
config.settings().getProperties().put("ebean.hana.generateUniqueDdl", "true"); // need to generate unique statements to prevent them from being filtered out as duplicates by the DdlRunner
|
||||
|
||||
config.setPackages(Arrays.asList("misc.migration.v1_0"));
|
||||
Database server = DatabaseFactory.create(config);
|
||||
Database server = config.build();
|
||||
migration.setServer(server);
|
||||
|
||||
// then we generate migration scripts for v1_0
|
||||
@@ -108,7 +106,7 @@ public class DbMigrationGenerateTest {
|
||||
// and now for v1_1
|
||||
config.setPackages(Arrays.asList("misc.migration.v1_1"));
|
||||
server.shutdown();
|
||||
server = DatabaseFactory.create(config);
|
||||
server = config.build();
|
||||
migration.setServer(server);
|
||||
assertThat(migration.generateMigration()).isEqualTo("1.1");
|
||||
assertThat(migration.generateMigration()).isNull(); // subsequent call
|
||||
@@ -128,7 +126,7 @@ public class DbMigrationGenerateTest {
|
||||
// and now for v1_2 with
|
||||
config.setPackages(Arrays.asList("misc.migration.v1_2"));
|
||||
server.shutdown();
|
||||
server = DatabaseFactory.create(config);
|
||||
server = config.build();
|
||||
migration.setServer(server);
|
||||
assertThat(migration.generateMigration()).isEqualTo("1.3");
|
||||
assertThat(migration.generateMigration()).isNull(); // subsequent call
|
||||
|
||||
@@ -2,8 +2,8 @@ package io.ebean.xtest.dbmigration;
|
||||
|
||||
import io.ebean.*;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.dbplatform.DbHistorySupport;
|
||||
import io.ebean.datasource.DataSourcePool;
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
@@ -217,7 +217,7 @@ public class DbMigrationTest extends BaseTestCase {
|
||||
if (history == null) {
|
||||
return;
|
||||
}
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName(server().name());
|
||||
config.loadFromProperties(server().pluginApi().config().getProperties());
|
||||
config.setDataSource(server().dataSource());
|
||||
@@ -227,7 +227,7 @@ public class DbMigrationTest extends BaseTestCase {
|
||||
config.setRegister(false);
|
||||
config.setPackages(Collections.singletonList("misc.migration.v1_1"));
|
||||
|
||||
Database tmpServer = DatabaseFactory.create(config);
|
||||
Database tmpServer = config.build();
|
||||
try {
|
||||
EHistory hist = new misc.migration.v1_1.EHistory();
|
||||
hist.setId(2);
|
||||
@@ -289,7 +289,7 @@ public class DbMigrationTest extends BaseTestCase {
|
||||
|
||||
// do some history tests with V1.1 models
|
||||
private void testReservedKeywords() {
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName(server().name());
|
||||
config.loadFromProperties(server().pluginApi().config().getProperties());
|
||||
config.setDataSource(server().dataSource());
|
||||
@@ -299,7 +299,7 @@ public class DbMigrationTest extends BaseTestCase {
|
||||
config.setRegister(false);
|
||||
config.setPackages(Collections.singletonList("misc.migration.v1_0"));
|
||||
|
||||
Database tmpServer = DatabaseFactory.create(config);
|
||||
Database tmpServer = config.build();
|
||||
try {
|
||||
ETable table = new misc.migration.v1_0.ETable();
|
||||
table.setFrom("foo");
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package io.ebean.xtest.event;
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.common.BeanList;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
@@ -27,7 +25,7 @@ public class BeanFindControllerTest extends BaseTestCase {
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
var config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
|
||||
config.setName("h2otherfind");
|
||||
config.setRegister(false);
|
||||
@@ -42,9 +40,9 @@ public class BeanFindControllerTest extends BaseTestCase {
|
||||
config.addClass(ECustomId.class);
|
||||
|
||||
EBasicFindController findController = new EBasicFindController();
|
||||
config.getFindControllers().add(findController);
|
||||
config.settings().getFindControllers().add(findController);
|
||||
|
||||
Database db = DatabaseFactory.create(config);
|
||||
Database db = config.build();
|
||||
|
||||
assertFalse(findController.calledInterceptFind);
|
||||
db.find(EBasic.class, 42);
|
||||
@@ -170,7 +168,7 @@ public class BeanFindControllerTest extends BaseTestCase {
|
||||
}
|
||||
|
||||
private Database prepareSoftRefs() {
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
|
||||
config.setName("h2otherfind");
|
||||
config.setRegister(false);
|
||||
@@ -185,9 +183,9 @@ public class BeanFindControllerTest extends BaseTestCase {
|
||||
config.addClass(SoftRefA.class);
|
||||
config.addClass(SoftRefB.class);
|
||||
|
||||
config.getFindControllers().add(new TestBeanFindController());
|
||||
config.settings().getFindControllers().add(new TestBeanFindController());
|
||||
|
||||
Database db = DatabaseFactory.create(config);
|
||||
Database db = config.build();
|
||||
|
||||
final SoftRefA softRefA = new SoftRefA();
|
||||
softRefA.setTitle("softRefA");
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
package io.ebean.xtest.event;
|
||||
|
||||
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.event.BeanDeleteIdRequest;
|
||||
import io.ebean.event.BeanPersistAdapter;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistRequest;
|
||||
import io.ebean.test.LoggedSql;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -151,7 +146,7 @@ public class BeanPersistControllerTest {
|
||||
}
|
||||
|
||||
private Database createDatabase(PersistAdapter persistAdapter) {
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("h2ebasicver");
|
||||
config.setRegister(false);
|
||||
config.setDefaultServer(false);
|
||||
@@ -165,7 +160,7 @@ public class BeanPersistControllerTest {
|
||||
config.addClass(UTDetail.class);
|
||||
|
||||
config.add(persistAdapter);
|
||||
return DatabaseFactory.create(config);
|
||||
return config.build();
|
||||
}
|
||||
|
||||
static class PersistAdapter extends BeanPersistAdapter {
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package io.ebean.xtest.event;
|
||||
|
||||
|
||||
import io.ebean.BeanState;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.event.BeanPostLoad;
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -49,7 +46,7 @@ public class BeanPostLoadTest extends BaseTestCase {
|
||||
|
||||
private Database createDatabase() {
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
|
||||
config.setName("h2ebasicver");
|
||||
config.setRegister(false);
|
||||
@@ -63,7 +60,7 @@ public class BeanPostLoadTest extends BaseTestCase {
|
||||
|
||||
config.add(postLoad);
|
||||
|
||||
return DatabaseFactory.create(config);
|
||||
return config.build();
|
||||
}
|
||||
|
||||
static class PostLoad implements BeanPostLoad {
|
||||
|
||||
+2
-4
@@ -2,11 +2,9 @@ package io.ebean.xtest.internal.server.transaction;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.DatabaseBuilder;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
import io.ebean.xtest.ForPlatform;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
@@ -132,7 +130,7 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
|
||||
private Database createOtherDatabase() {
|
||||
|
||||
DatabaseBuilder config = new DatabaseConfig();
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("h2ebasicver");
|
||||
config.loadFromProperties();
|
||||
config.setDdlGenerate(true);
|
||||
@@ -145,6 +143,6 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
config.addClass(UTMaster.class);
|
||||
config.addClass(UTDetail.class);
|
||||
|
||||
return DatabaseFactory.create(config);
|
||||
return config.build();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user