Dalesbred 是一个致力于让 Java 更好地访问数据库的库。Dalesbred 认为 SQL 是访问数据库的好方法,但 JDBC 作为 API 会带来痛苦。因此,它使用一组帮助程序包装 JDBC,同时仍提供对低级功能的访问。
Dalesbred 中的大多数事情都是通过Database的实例发生的。它负责管理 JDBC 连接,因此在典型应用程序中,您应该只配置一个实例——除非您需要连接多个数据库。最简单的方法是手动指定设置:
Database db = Database.forUrlAndCredentials("jdbc:example-url", "login", "password");
请注意,这不会执行连接池,因此可能不是您在生产中配置系统的首选方式。在容器中,您可能希望从 JNDI中查找命名的DataSource :
Database db = Database.forJndiDataSource("java:comp/env/jdbc/ExampleDb");
Database db = Database.forDataSource(myDataSource);
如果您使用的是Spring Framework,请参阅 Spring部分,了解如何将 Dalesbred 与其集成。
运行产生基本类型的查询很简单:
- List
newIds = db.findAll(Integer.class, - "select id from department where created_date > ?", date);
有几种方法可以获取多列的结果。首先,您可以创建一个匹配的构造函数:
- List
departments = - db.findAll(Department.class, "select id, name from department");
-
- public final class Department {
- private final int id;
- private final String name;
-
- @DalesbredInstantiator
- public Department(int id, String name) {
- this.id = id;
- this.name = name;
- }
-
- ...
- }
构造函数的DalesbredInstantiator注释是可选的,但有助于 Dalesbred 在有多个构造函数时做出明确的决定。它也可用作有用的文档。最后,它可以配置为静态分析器的入口点,这样它们就不会抱怨未使用的构造函数。 |
除了构造函数,您还可以@DalesbredInstantiator
在返回类实例的静态方法上使用。
第二个选项是使用字段或设置器绑定值。以下示例使用默认构造函数进行实例化、字段绑定 forid
和 setter for name
:
- List
departments = - db.findAll(Department.class, "select id, name from department");
-
- ...
-
- public final class Department {
- public int id;
- private String name;
-
- public void setName(String name) {
- this.name = name;
- }
- }
如果你有嵌套对象,你可以绑定到它们,只要路径中的所有对象都被实例化:
- List
departments = - db.findAll(Employee.class, "select id, first_name as \"name.first\", last_name as \"name.last\" from employee");
-
- ...
-
- public final class Employee {
- public int id;
- public final Name name = new Name();
- }
-
- public final class Name {
- public String first;
- public String last;
- }
您还可以将结果直接转换为地图:
- Map
namesByIds = db.findMap( - Integer.class, String.class, "select id, name from department");
-
- // first column is used for key, rest for instantiating the value
- Map
departmentsByIds = db.findMap( - Integer.class, Department.class, "select id, id, name from department");
如果由于某种原因您不想将结果映射到您自己的类中,您可以要求一个ResultTable,它基本上是一个ResultSet的分离表示:
ResultTable employees = db.findTable("select * from employee");
或者,您可以提供自己的RowMapper或 ResultSetProcessor -实现来代替类并手动处理结果集,但通常这应该是不必要的。
- import static org.dalesbred.query.SqlQuery.query;
-
- SqlQuery query = query("select id, name from department where update_timestamp > ?", date);
- db.findAll(Department.class, query);
-
- db.findAll(Department.class,
- "select id, name from department where update_timestamp > ?", date);
通常你想使用后一种形式,但每隔一段时间,能够使用它的参数传递查询是很有用的。在这些情况下,您需要使用第一种形式。一个示例是当您动态构建查询时:
db.findAll(Department.class, buildDepartmentQuery(form));
除了在 SQL 语句中使用位置参数之外,您还可以命名参数:
- import static org.dalesbred.query.SqlQuery.namedQuery;
-
- Map
values = new HashMap<>(); - values.put("firstName", "John");
- values.put("lastName", "Doe");
-
- db.findAll(Department.class, namedQuery("select id from employee " +
- " where first_name = :firstName " +
- " and last_name = :lastName", values));
除了Map,您还可以将常规对象namedQuery
作为值的来源传递。参数名称映射到对象的属性或字段。最后,如果你想要详细的控制,你可以通过你自己的 VariableResolver实现来解析变量。
没有用于构建查询的高级 API,但QueryBuilder 可以帮助您构建动态查询。它基本上只是一个StringBuilder ,它还跟踪参数。因此,您可以这样说代码:
- QueryBuilder qb = new QueryBuilder("select id, name, status from document");
- if (status != null)
- qb.append(" where status=?", status);
-
- db.findAll(Document.class, qb.build());
使用静态查询的好处是 IDEA 和 Dalesbred IDEA 插件知道如何分析它们:它们可以根据数据库模式和结果类进行验证。动态构建查询时,您将失去这些好处。如果您需要许多动态查询,请考虑在 QueryBuilder 之上构建更高级别的抽象。 |
要在事务中执行一堆操作,请使用TransactionCallback 或VoidTransactionCallback:
- db.withTransaction(tx -> {
- // transactional operations
- ...
- return result;
- });
-
- db.withVoidTransaction(tx -> {
- // transactional operations
- ...
- });
或者,您还可以为这些调用传递Isolation或 Propagation。
如果您使用Spring Framework,Dalesbred 可以与 Spring 的事务管理器集成。有关详细信息,请参阅Spring部分。
如果您在没有显式事务的情况下调用数据库,则默认情况下,每次调用都会启动一个新事务。您可以禁止这样做:在这种情况下,对于没有活动事务的调用会引发异常:
db.setAllowImplicitTransactions(false);
通常 Dalesbred 会根据数据库结果自动检测实例化类的最佳方式。这有时会导致令人惊讶的结果。如果您希望更明确,可以使用DalesbredInstantiator注释您首选的构造函数。这将导致 Dalesbred 忽略所有其他构造函数。
只需将InputStream 或Reader传递给查询,您就可以将大对象(blob 和 clob)流式传输到数据库。同样,您可以通过询问 InputStream 或 Reader 来阅读它们。
- try (InputStream in = new FileInputStream(name)) {
- db.update("insert into my_file (name, contents) values (?,?)", name, in);
- }
-
- try (InputStream in = db.findUnique(InputStream.class,
- "select contents from my_file where name=?", name)) {
- ...
- }
请注意,返回的 InputStream 或 Reader 仅在活动事务期间有效。 |
有时您需要将数据库值转换为您自己的自定义类型,反之亦然。为此,您可以将您的函数注册到TypeConversionRegistry:
- TypeConversionRegistry conversions = db.getTypeConversionRegistry();
-
- // register conversions from database and to database types separately
- conversions.registerConversionFromDatabase(
- String.class, EmailAddress.class, MyConversions::stringToEmail);
- conversions.registerConversionToDatabase(
- EmailAddress.class, String.class, MyConversions::emailToString);
-
- // or register both conversions with one call
- conversions.registerConversions(
- String.class, EmailAddress.class, MyConversions::stringToEmail, MyConversions::emailToString);
Dalesbred 为以下类提供内置类型转换:
型号类型 | 数据库类型 | |
---|---|---|
java.net.URI | ← → | 细绳 |
java.net.URL | ← → | 细绳 |
java.util.TimeZone | ← → | 细绳 |
短/整数/长/浮点/双 | ← | 数字 |
大整数/大小数 | ← | 数字 |
大整数 | → | 大十进制 |
字符串/java.io.Reader | ← | 克洛布 |
字节/java.io.InputStream | ← | 斑点 |
org.w3c.dom.Document | ← | SQLXML |
java.time.Instant | ← → | 时间戳 |
java.time.LocalDateTime | ← → | 时间戳 |
java.time.LocalTime | ← → | 时间 |
java.time.ZoneId | ← → | 细绳 |
java.time.LocalDate | ← → | java.util.Date/java.sql.Date |
Dalesbred 对Kotlin没有必需的依赖项,但带有一组扩展方法以使 Kotlin 更好用。只需从中导入所有内容org.dalesbred.integration.kotlin
,您就可以开始了:
- import org.dalesbred.integration.kotlin.*
-
- ...
-
- fun findEmployees() = db.findAll
(""" - select id, name, salary
- from employee
- order by name, id
- """)
如果在类路径上检测到来自Joda-Time,Dalesbred 将自动注册Joda-Time的 DateTime、LocalDate 和LocalTime到java.sql.Timestamp、 java.sql.Date和java.sql.Time之间的类型转换。
Dalesbred 支持与Spring Framework 及其事务管理的集成。要集成 Dalesbred,请创建一个继承自 DalesbredConfigurationSupport的配置类,并为DataSource和 PlatformTransactionManager 指定 beans 。因此,最小配置将类似于以下内容:
- @Configuration
- @EnableTransactionManagement
- public class MyDatabaseConfiguration extends DalesbredConfigurationSupport {
-
- @Bean
- public DataSource dataSource() {
- return new JndiDataSourceLookup().getDataSource("jdbc/my-database");
- }
-
- @Bean
- public PlatformTransactionManager transactionManager() {
- return new DataSourceTransactionManager(dataSource());
- }
- }
在此之后,您可以在 bean 中正常注入数据库。
如果您使用的是IntelliJ IDEA,请查看 Dalesbred IDEA 插件,它可以检查常见错误(例如查询参数和查询之间的不匹配)。
通过在您的项目中包含dalesbred-junit工件作为测试依赖项,您将获得编写事务测试用例的支持:
- public class MyTest {
-
- private final Database db =
- TestDatabaseProvider.databaseForProperties("testdb.properties");
-
- @Rule
- public final TransactionalTests tx = new TransactionalTests(db);
-
- @Test
- public void simpleTest() {
- assertEquals("hello, world!",
- db.queryForUnique(String.class "select 'hello, world!'");
- }
- }
查看dalesbred/src/test/kotlin下的测试用例 以获取更多使用示例。