• Java Dalesbred库访问数据库


    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 与其集成。

    找东西

    运行产生基本类型的查询很简单:

    1. List newIds = db.findAll(Integer.class,
    2. "select id from department where created_date > ?", date);

    有几种方法可以获取多列的结果。首先,您可以创建一个匹配的构造函数:

    1. List departments =
    2. db.findAll(Department.class, "select id, name from department");
    3. public final class Department {
    4. private final int id;
    5. private final String name;
    6. @DalesbredInstantiator
    7. public Department(int id, String name) {
    8. this.id = id;
    9. this.name = name;
    10. }
    11. ...
    12. }
    构造函数的DalesbredInstantiator注释是可选的,但有助于 Dalesbred 在有多个构造函数时做出明确的决定。它也可用作有用的文档。最后,它可以配置为静态分析器的入口点,这样它们就不会抱怨未使用的构造函数。

    除了构造函数,您还可以@DalesbredInstantiator在返回类实例的静态方法上使用。

    第二个选项是使用字段或设置器绑定值。以下示例使用默认构造函数进行实例化、字段绑定 forid和 setter for name

    1. List departments =
    2. db.findAll(Department.class, "select id, name from department");
    3. ...
    4. public final class Department {
    5. public int id;
    6. private String name;
    7. public void setName(String name) {
    8. this.name = name;
    9. }
    10. }

    如果你有嵌套对象,你可以绑定到它们,只要路径中的所有对象都被实例化:

    1. List departments =
    2. db.findAll(Employee.class, "select id, first_name as \"name.first\", last_name as \"name.last\" from employee");
    3. ...
    4. public final class Employee {
    5. public int id;
    6. public final Name name = new Name();
    7. }
    8. public final class Name {
    9. public String first;
    10. public String last;
    11. }

    您还可以将结果直接转换为地图:

    1. Map namesByIds = db.findMap(
    2. Integer.class, String.class, "select id, name from department");
    3. // first column is used for key, rest for instantiating the value
    4. Map departmentsByIds = db.findMap(
    5. Integer.class, Department.class, "select id, id, name from department");

    如果由于某种原因您不想将结果映射到您自己的类中,您可以要求一个ResultTable,它基本上是一个ResultSet的分离表示:

    ResultTable employees = db.findTable("select * from employee");
    

    或者,您可以提供自己的RowMapper或 ResultSetProcessor -实现来代替类并手动处理结果集,但通常这应该是不必要的。

    更新

    正常更新很简单,因为我们不需要做太多工作来映射结果:

    int modifiedRows = db.update("delete from user where id=?", 42);
    

    如果您计划从更新中返回内容,就 Dalesbred 而言,它们是查询:

    int id = db.findUniqueInt("insert into department (name) values ('foo') returning id");
    

    查询

    SqlQuery 与查询参数

    所有方法都有两种变体:一个实现采用SqlQuery作为参数,另一个实现采用String和可变数量的参数。后者只是更方便的方法,这意味着以下代码片段在功能上是相同的:

    1. import static org.dalesbred.query.SqlQuery.query;
    2. SqlQuery query = query("select id, name from department where update_timestamp > ?", date);
    3. db.findAll(Department.class, query);
    4. db.findAll(Department.class,
    5. "select id, name from department where update_timestamp > ?", date);

    通常你想使用后一种形式,但每隔一段时间,能够使用它的参数传递查询是很有用的。在这些情况下,您需要使用第一种形式。一个示例是当您动态构建查询时:

    db.findAll(Department.class, buildDepartmentQuery(form));
    

    命名查询

    除了在 SQL 语句中使用位置参数之外,您还可以命名参数:

    1. import static org.dalesbred.query.SqlQuery.namedQuery;
    2. Map values = new HashMap<>();
    3. values.put("firstName", "John");
    4. values.put("lastName", "Doe");
    5. db.findAll(Department.class, namedQuery("select id from employee " +
    6. " where first_name = :firstName " +
    7. " and last_name = :lastName", values));

    除了Map,您还可以将常规对象namedQuery作为值的来源传递。参数名称映射到对象的属性或字段。最后,如果你想要详细的控制,你可以通过你自己的 VariableResolver实现来解析变量。

    动态构建查询

    没有用于构建查询的高级 API,但QueryBuilder 可以帮助您构建动态查询。它基本上只是一个StringBuilder ,它还跟踪参数。因此,您可以这样说代码:

    1. QueryBuilder qb = new QueryBuilder("select id, name, status from document");
    2. if (status != null)
    3. qb.append(" where status=?", status);
    4. db.findAll(Document.class, qb.build());
    使用静态查询的好处是 IDEA 和 Dalesbred IDEA 插件知道如何分析它们:它们可以根据数据库模式和结果类进行验证。动态构建查询时,您将失去这些好处。如果您需要许多动态查询,请考虑在 QueryBuilder 之上构建更高级别的抽象。

    交易

    事务回调

    要在事务中执行一堆操作,请使用TransactionCallback 或VoidTransactionCallback

    1. db.withTransaction(tx -> {
    2. // transactional operations
    3. ...
    4. return result;
    5. });
    6. db.withVoidTransaction(tx -> {
    7. // transactional operations
    8. ...
    9. });

    或者,您还可以为这些调用传递Isolation或 Propagation

    外部事务管理器

    如果您使用Spring Framework,Dalesbred 可以与 Spring 的事务管理器集成。有关详细信息,请参阅Spring部分。

    隐式事务

    如果您在没有显式事务的情况下调用数据库,则默认情况下,每次调用都会启动一个新事务。您可以禁止这样做:在这种情况下,对于没有活动事务的调用会引发异常:

    db.setAllowImplicitTransactions(false);
    

    嵌套事务

    如果您的数据库支持嵌套事务,则支持它们:

    1. db.withTransaction(Propagation.NESTED, tx -> {
    2. ...
    3. });

    其他功能

    显式实例化器

    通常 Dalesbred 会根据数据库结果自动检测实例化类的最佳方式。这有时会导致令人惊讶的结果。如果您希望更明确,可以使用DalesbredInstantiator注释您首选的构造函数。这将导致 Dalesbred 忽略所有其他构造函数。

    大型物体

    只需将InputStream 或Reader传递给查询,您就可以将大对象(blob 和 clob)流式传输到数据库。同样,您可以通过询问 InputStream 或 Reader 来阅读它们。

    1. try (InputStream in = new FileInputStream(name)) {
    2. db.update("insert into my_file (name, contents) values (?,?)", name, in);
    3. }
    4. try (InputStream in = db.findUnique(InputStream.class,
    5. "select contents from my_file where name=?", name)) {
    6. ...
    7. }
    请注意,返回的 InputStream 或 Reader 仅在活动事务期间有效。

    自定义类型转换

    有时您需要将数据库值转换为您自己的自定义类型,反之亦然。为此,您可以将您的函数注册到TypeConversionRegistry

    1. TypeConversionRegistry conversions = db.getTypeConversionRegistry();
    2. // register conversions from database and to database types separately
    3. conversions.registerConversionFromDatabase(
    4. String.class, EmailAddress.class, MyConversions::stringToEmail);
    5. conversions.registerConversionToDatabase(
    6. EmailAddress.class, String.class, MyConversions::emailToString);
    7. // or register both conversions with one call
    8. conversions.registerConversions(
    9. 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,您就可以开始了:

    1. import org.dalesbred.integration.kotlin.*
    2. ...
    3. fun findEmployees() = db.findAll("""
    4. select id, name, salary
    5. from employee
    6. order by name, id
    7. """)

    乔达时间

    如果在类路径上检测到来自Joda-Time,Dalesbred 将自动注册Joda-Time的 DateTimeLocalDate 和LocalTimejava.sql.Timestamp、 java.sql.Datejava.sql.Time之间的类型转换

    春天

    Dalesbred 支持与Spring Framework 及其事务管理的集成。要集成 Dalesbred,请创建一个继承自 DalesbredConfigurationSupport的配置类,并为DataSource和 PlatformTransactionManager 指定 beans 。因此,最小配置将类似于以下内容:

    1. @Configuration
    2. @EnableTransactionManagement
    3. public class MyDatabaseConfiguration extends DalesbredConfigurationSupport {
    4. @Bean
    5. public DataSource dataSource() {
    6. return new JndiDataSourceLookup().getDataSource("jdbc/my-database");
    7. }
    8. @Bean
    9. public PlatformTransactionManager transactionManager() {
    10. return new DataSourceTransactionManager(dataSource());
    11. }
    12. }

    在此之后,您可以在 bean 中正常注入数据库。

    我理解这个想法

    如果您使用的是IntelliJ IDEA,请查看 Dalesbred IDEA 插件,它可以检查常见错误(例如查询参数和查询之间的不匹配)。

    测试支持

    通过在您的项目中包含dalesbred-junit工件作为测试依赖项,您将获得编写事务测试用例的支持:

    1. public class MyTest {
    2. private final Database db =
    3. TestDatabaseProvider.databaseForProperties("testdb.properties");
    4. @Rule
    5. public final TransactionalTests tx = new TransactionalTests(db);
    6. @Test
    7. public void simpleTest() {
    8. assertEquals("hello, world!",
    9. db.queryForUnique(String.class "select 'hello, world!'");
    10. }
    11. }

    更多示例

    查看dalesbred/src/test/kotlin下的测试用例 以获取更多使用示例。

    下载

    摇篮

    1. repositories {
    2. mavenCentral()
    3. }
    4. dependencies {
    5. implementation("org.dalesbred:dalesbred:1.3.5")
    6. }

    马文

    1. org.dalesbred
    2. dalesbred
    3. 1.3.5
  • 相关阅读:
    uCOSii中的事件标志组
    嵌入式系统的开发概述
    详解CAN通信的标识符掩码和标识符列表两种过滤机制
    什么是Apollo自动驾驶平台?
    hive抽取mysql里的表,如果mysql表没有时间字段如何做增量抽取数据
    使用 Monaco Editor 开发一个 SQL 编辑器
    超越OpenCV速度的MorphologyEx函数实现(特别是对于二值图,速度是CV的4倍左右)。
    R语言Sys.Date函数获取当前日期、将独立的年、月、日信息转化为对应的日期(Year, Month, and Day into a Date)
    SJ/T 11294-2018 防静电地坪涂料检测
    企业微信 API 接口调用教程:深入解析企业微信 API 的用法
  • 原文地址:https://blog.csdn.net/allway2/article/details/126909577