• Java 使用 JDBI 库访问MySQL 数据库


    在本教程中,我们将展示如何使用 JDBI 处理数据。我们选择 MySQL 作为我们的数据库。

    JDBI是一个建立在 JDBC 之上的便利库。它使数据库编程变得更加容易。它管理异常。它具有用于自动资源管理和将结果集映射到类的工具。JDBI 在概念上类似于 Spring 的JdbcTemplate。

    实例通过DBI实例提供与数据库的连接Handle。 Handle表示与数据库系统的连接;它是 JDBC Connection 对象的包装器。

    JDBI 提供了两种不同的风格 API:流式风格和对象风格。

    在 MySQL 中创建数据库

    在本节中,我们testdb在 MySQL 中创建一个新数据库。我们使用mysql监视器来完成这项工作,但我们也可以使用 NetBeans 数据库工具。

    cars_mysql.sql

    1. DROP TABLE IF EXISTS Cars;
    2. CREATE TABLE Cars(Id INT PRIMARY KEY AUTO_INCREMENT,
    3. Name TEXT, Price INT) ENGINE=InnoDB;
    4. INSERT INTO Cars(Name, Price) VALUES('Audi', 52642);
    5. INSERT INTO Cars(Name, Price) VALUES('Mercedes', 57127);
    6. INSERT INTO Cars(Name, Price) VALUES('Skoda', 9000);
    7. INSERT INTO Cars(Name, Price) VALUES('Volvo', 29000);
    8. INSERT INTO Cars(Name, Price) VALUES('Bentley', 350000);
    9. INSERT INTO Cars(Name, Price) VALUES('Citroen', 21000);
    10. INSERT INTO Cars(Name, Price) VALUES('Hummer', 41400);
    11. INSERT INTO Cars(Name, Price) VALUES('Volkswagen', 21600);

    这是在 MySQL 中创建Cars表的 SQL。

    要创建数据库和表,我们使用mysql 监控工具。

    $ sudo service mysql start
    

    MySQL 是用sudo service mysql start命令启动的。

    $ mysql -u testuser -p 
    

    mysql我们使用监视器 连接到数据库。

    1. mysql> CREATE DATABASE testdb;
    2. Query OK, 1 row affected (0.02 sec)

    使用该CREATE DATABASE语句,将创建一个新数据库。

    1. mysql> USE testdb;
    2. mysql> SOURCE cars_mysql.sql

    使用source命令,我们加载并执行cars_mysql.sql 文件。

    1. mysql> SELECT * FROM Cars;
    2. +----+------------+--------+
    3. | Id | Name | Price |
    4. +----+------------+--------+
    5. | 1 | Audi | 52642 |
    6. | 2 | Mercedes | 57127 |
    7. | 3 | Skoda | 9000 |
    8. | 4 | Volvo | 29000 |
    9. | 5 | Bentley | 350000 |
    10. | 6 | Citroen | 21000 |
    11. | 7 | Hummer | 41400 |
    12. | 8 | Volkswagen | 21600 |
    13. +----+------------+--------+
    14. 8 rows in set (0.00 sec)

    我们验证数据。

    pom.xml 文件

    这些示例将使用以下 Maven POM 文件:

    pom.xml
    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <modelVersion>4.0.0modelVersion>
    6. <groupId>com.zetcodegroupId>
    7. <artifactId>JDBIExartifactId>
    8. <version>1.0-SNAPSHOTversion>
    9. <packaging>jarpackaging>
    10. <properties>
    11. <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    12. <maven.compiler.source>1.8maven.compiler.source>
    13. <maven.compiler.target>1.8maven.compiler.target>
    14. properties>
    15. <dependencies>
    16. <dependency>
    17. <groupId>org.jdbigroupId>
    18. <artifactId>jdbiartifactId>
    19. <version>2.73version>
    20. dependency>
    21. <dependency>
    22. <groupId>mysqlgroupId>
    23. <artifactId>mysql-connector-javaartifactId>
    24. <version>5.1.39version>
    25. dependency>
    26. dependencies>
    27. project>

    我们已经为 JDBI 库和 MySQL 驱动程序定义了依赖关系。

    流畅的 API

    在以下示例中,我们将使用 JDBI Fluent API 来处理 MySQL 数据库。

    检索所有汽车

    在第一个示例中,我们从Cars表中获取所有汽车。

    JDBIEx.java
    1. package com.zetcode;
    2. import java.util.List;
    3. import java.util.Map;
    4. import org.skife.jdbi.v2.DBI;
    5. import org.skife.jdbi.v2.Handle;
    6. import org.skife.jdbi.v2.Query;
    7. public class JDBIEx {
    8. public static void main(String[] args) {
    9. Handle handle = null;
    10. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    11. "testuser", "test623");
    12. String sql = "SELECT * FROM Cars";
    13. try {
    14. handle = dbi.open();
    15. Query> q = handle.createQuery(sql);
    16. List> l = q.list();
    17. for (Map m : l) {
    18. System.out.printf("%d ", m.get("Id"));
    19. System.out.printf("%s ", m.get("Name"));
    20. System.out.println(m.get("Price"));
    21. }
    22. } finally {
    23. if (handle != null) {
    24. handle.close();
    25. }
    26. }
    27. }
    28. }

    该示例连接到testdb数据库并从Cars表中检索所有汽车。

    1. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    2. "testuser", "test623");

    DBI使用该类 为数据库创建一个访问点。

    handle = dbi.open();
    

    使用HandleDBI's open()方法创建数据库。它表示与数据库的连接。与数据库的连接是使用DriverManager.

    Query> q = handle.createQuery(sql);
    

    使用该方法创建一个Query对象createQuery()

    List> l = q.list();
    

    从查询对象中,我们得到一个键/值对列表。

    1. for (Map m : l) {
    2. System.out.printf("%d ", m.get("Id"));
    3. System.out.printf("%s ", m.get("Name"));
    4. System.out.println(m.get("Price"));
    5. }

    我们遍历列表并打印所有列。

    1. } finally {
    2. if (handle != null) {
    3. handle.close();
    4. }
    5. }

    最后,我们关闭手柄。

    1. 1 Audi 52642
    2. 2 Mercedes 57127
    3. 3 Skoda 9000
    4. 4 Volvo 29000
    5. 5 Bentley 350000
    6. 6 Citroen 21000
    7. 7 Hummer 41400
    8. 8 Volkswagen 21600

    这是示例的输出。

    通过 ID 检索汽车

    在下一个示例中,我们Cars 通过 ID 从表中获取汽车名称。

    JDBIEx2.java
    1. package com.zetcode;
    2. import java.util.Map;
    3. import org.skife.jdbi.v2.DBI;
    4. import org.skife.jdbi.v2.Handle;
    5. import org.skife.jdbi.v2.Query;
    6. import org.skife.jdbi.v2.util.StringColumnMapper;
    7. public class JDBIEx2 {
    8. public static void main(String[] args) {
    9. Handle handle = null;
    10. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    11. "testuser", "test623");
    12. try {
    13. handle = dbi.open();
    14. String sql = "SELECT Name FROM Cars WHERE Id = ?";
    15. Query> q = handle.createQuery(sql);
    16. q.bind(0, 1);
    17. String carName = q.map(StringColumnMapper.INSTANCE).first();
    18. System.out.println(carName);
    19. } finally {
    20. if (handle != null) {
    21. handle.close();
    22. }
    23. }
    24. }
    25. }

    在示例中,我们从Cars表中选择汽车名称。SQL 查询采用稍后绑定的参数。

    String sql = "SELECT Name FROM Cars WHERE Id = ?";
    

    这是用于从表中选择汽车名称的 SQL 代码。问号是稍后在代码中填写的标记。

    Query> q = handle.createQuery(sql);
    

    Query从 SQL 语句创建 一个新对象。

    q.bind(0, 1);
    

    使用该bind()方法,我们绑定缺少的参数。该参数是按位置绑定的。

    String carName = q.map(StringColumnMapper.INSTANCE).first();
    

    我们将结果集的一列映射StringColumnMapper 到字符串类型。该first()方法用于返回一个值。

    System.out.println(carName);
    

    汽车的名称打印在控制台上。

    数据源

    在此示例中,我们使用数据源连接到数据库。数据源的使用提高了应用程序的性能和可伸缩性。

    db.properties
    1. # mysql properties
    2. mysql.driver=com.mysql.jdbc.Driver
    3. mysql.url=jdbc:mysql://localhost:3306/testdb
    4. mysql.username=testuser
    5. mysql.password=test623

    db.properties文件中,我们有连接属性。

    图:数据库属性

    该文件被放置在项目的Resources目录中。

    JDBIEx3.java
    1. package com.zetcode;
    2. import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
    3. import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
    4. import java.io.FileInputStream;
    5. import java.io.FileNotFoundException;
    6. import java.io.IOException;
    7. import java.util.Map;
    8. import java.util.Properties;
    9. import org.skife.jdbi.v2.DBI;
    10. import org.skife.jdbi.v2.Handle;
    11. import org.skife.jdbi.v2.Query;
    12. import org.skife.jdbi.v2.util.IntegerColumnMapper;
    13. public class JDBIEx3 {
    14. public static MysqlDataSource getMySQLDataSource() throws
    15. FileNotFoundException, IOException {
    16. Properties props = new Properties();
    17. FileInputStream fis = null;
    18. MysqlDataSource ds = null;
    19. fis = new FileInputStream("src/main/Resources/db.properties");
    20. props.load(fis);
    21. ds = new MysqlConnectionPoolDataSource();
    22. ds.setURL(props.getProperty("mysql.url"));
    23. ds.setUser(props.getProperty("mysql.username"));
    24. ds.setPassword(props.getProperty("mysql.password"));
    25. return ds;
    26. }
    27. public static void main(String[] args) throws IOException {
    28. Handle handle = null;
    29. MysqlDataSource ds = getMySQLDataSource();
    30. DBI dbi = new DBI(ds);
    31. try {
    32. handle = dbi.open();
    33. String sql = "SELECT Price FROM Cars WHERE Id = ?";
    34. Query> q = handle.createQuery(sql);
    35. q.bind(0, 1);
    36. Integer price = q.map(IntegerColumnMapper.WRAPPER).first();
    37. System.out.println(price);
    38. } finally {
    39. if (handle != null) {
    40. handle.close();
    41. }
    42. }
    43. }
    44. }

    该示例选择通过 ID 找到的汽车的价格。

    1. fis = new FileInputStream("src/main/Resources/db.properties");
    2. props.load(fis);

    我们从Resources目录加载属性。

    1. ds = new MysqlConnectionPoolDataSource();
    2. ds.setURL(props.getProperty("mysql.url"));
    3. ds.setUser(props.getProperty("mysql.username"));
    4. ds.setPassword(props.getProperty("mysql.password"));

    MysqlConnectionPoolDataSource已创建。我们从属性文件中设置参数。

    Integer price = q.map(IntegerColumnMapper.WRAPPER).first();
    

    由于 SQL 查询返回一个整数,因此我们使用IntegerColumnMapper该类。

    withHandle() 方法

    该类DBI有一个名为 的便捷方法withHandle(),它管理句柄的生命周期并将其交给回调以供客户端使用。

    JDBIEx4.java
    1. package com.zetcode;
    2. import org.skife.jdbi.v2.DBI;
    3. import org.skife.jdbi.v2.Handle;
    4. import org.skife.jdbi.v2.util.IntegerColumnMapper;
    5. public class JDBIEx4 {
    6. public static void main(String[] args) {
    7. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    8. "testuser", "test623");
    9. String sql = "SELECT Price FROM Cars WHERE Id = :id";
    10. int id = 3;
    11. Integer price = dbi.withHandle((Handle h) -> {
    12. return h.createQuery(sql)
    13. .map(IntegerColumnMapper.WRAPPER)
    14. .bind("id", id)
    15. .first();
    16. });
    17. System.out.println(price);
    18. }
    19. }

    该示例选择由 ID 标识的汽车价格。

    String sql = "SELECT Price FROM Cars WHERE Id = :id";
    

    此 SQL 查询使用命名参数。

    1. Integer price = dbi.withHandle((Handle h) -> {
    2. return h.createQuery(sql)
    3. .map(IntegerColumnMapper.WRAPPER)
    4. .bind("id", id)
    5. .first();
    6. });

    创建并执行查询,我们不必担心关闭句柄。

    映射自定义类

    可以将自定义类映射到结果集。映射类必须实现ResultSetMapper接口。

    Car.java
    1. package com.zetcode;
    2. public class Car {
    3. private Long Id;
    4. private String Name;
    5. private int Price;
    6. public Car(Long Id, String Name, int Price) {
    7. this.Id = Id;
    8. this.Name = Name;
    9. this.Price = Price;
    10. }
    11. public Long getId() {
    12. return Id;
    13. }
    14. public void setId(Long Id) {
    15. this.Id = Id;
    16. }
    17. public String getName() {
    18. return Name;
    19. }
    20. public void setName(String Name) {
    21. this.Name = Name;
    22. }
    23. public int getPrice() {
    24. return Price;
    25. }
    26. public void setPrice(int Price) {
    27. this.Price = Price;
    28. }
    29. @Override
    30. public String toString() {
    31. return "Car{" + "Id=" + Id + ", Name=" + Name + ", Price=" + Price + '}';
    32. }
    33. }

    这是Car我们要将结果集映射到的自定义类。

    CarMapper.java
    1. package com.zetcode;
    2. import java.sql.ResultSet;
    3. import java.sql.SQLException;
    4. import org.skife.jdbi.v2.StatementContext;
    5. import org.skife.jdbi.v2.tweak.ResultSetMapper;
    6. public class CarMapper implements ResultSetMapper {
    7. @Override
    8. public Car map(int idx, ResultSet rs, StatementContext ctx) throws SQLException {
    9. return new Car(rs.getLong("Id"), rs.getString("Name"), rs.getInt("Price"));
    10. }
    11. }

    我们提供映射类。它返回一个Car填充了结果集中数据的新对象。

    JDBIEx5.java
    1. package com.zetcode;
    2. import org.skife.jdbi.v2.DBI;
    3. import org.skife.jdbi.v2.Handle;
    4. public class JDBIEx5 {
    5. public static void main(String[] args) {
    6. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    7. "testuser", "test623");
    8. String sql = "SELECT * FROM Cars WHERE Id = :id";
    9. int id = 3;
    10. Car car = dbi.withHandle((Handle h) -> {
    11. return h.createQuery(sql)
    12. .map(new CarMapper())
    13. .bind("id", id)
    14. .first();
    15. });
    16. System.out.println(car);
    17. }
    18. }

    该示例Car从由其 ID 标识的表中选择一个对象。

    1. Car car = dbi.withHandle((Handle h) -> {
    2. return h.createQuery(sql)
    3. .map(new CarMapper())
    4. .bind("id", id)
    5. .first();
    6. });

    自定义CarMapper对象被传递给该map() 方法。

    批量操作

    批处理允许我们将相关的 SQL 语句分组到一个批处理中,并通过一次调用数据库来提交它们。这可以显着提高我们应用程序的性能。

    批处理操作不是原子的;他们没有提供全有或全无的解决方案。例如,如果我们创建了不正确的 INSERT 语句,它会失败,但会执行其他 INSERT 语句。

    JDBIEx6.java
    1. package com.zetcode;
    2. import org.skife.jdbi.v2.Batch;
    3. import org.skife.jdbi.v2.DBI;
    4. import org.skife.jdbi.v2.Handle;
    5. public class JDBIEx6 {
    6. public static void main(String[] args) {
    7. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    8. "testuser", "test623");
    9. Handle handle = dbi.open();
    10. Batch batch = handle.createBatch();
    11. batch.add("DROP TABLE IF EXISTS Friends");
    12. batch.add("CREATE TABLE Friends(Id INT AUTO_INCREMENT PRIMARY KEY, Name TEXT)");
    13. batch.add("INSERT INTO Friends(Name) VALUES ('Monika')");
    14. batch.add("INSERT INTO Friends(Name) VALUES ('Tom')");
    15. batch.add("INSERT INTO Friends(Name) VALUES ('Jane')");
    16. batch.add("INSERT INTO Friends(Name) VALUES ('Robert')");
    17. batch.execute();
    18. }
    19. }

    该示例创建一个新Friends表。SQL 命令被分组为一个批处理操作。

    Batch batch = handle.createBatch();
    

    Batch代表一组未准备好的语句;它是使用该createBatch()方法创建的。

    batch.add("DROP TABLE IF EXISTS Friends");
    

    add()方法将语句添加到批处理中。

    batch.execute();
    

    使用该execute()方法执行批处理。

    事务

    事务是针对 一个或多个数据库中的数据的数据库操作的原子单元。事务中所有 SQL 语句的影响可以全部提交给数据库,也可以全部回滚。

    另请注意,在 MySQL 中,DROP TABLE 和 CREATE TABLE 等 DDL 语句会导致对事务的隐式提交。

    JDBIEx7.java
    1. package com.zetcode;
    2. import org.skife.jdbi.v2.Batch;
    3. import org.skife.jdbi.v2.DBI;
    4. import org.skife.jdbi.v2.Handle;
    5. import org.skife.jdbi.v2.TransactionStatus;
    6. import org.skife.jdbi.v2.VoidTransactionCallback;
    7. public class JDBIEx7 {
    8. public static void main(String[] args) {
    9. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    10. "testuser", "test623");
    11. dbi.inTransaction(new VoidTransactionCallback() {
    12. @Override
    13. protected void execute(Handle handle, TransactionStatus status)
    14. throws Exception {
    15. Batch batch = handle.createBatch();
    16. batch.add("DROP TABLE IF EXISTS Friends");
    17. batch.add("CREATE TABLE Friends(Id INT AUTO_INCREMENT PRIMARY KEY, Name TEXT)");
    18. batch.add("INSERT INTO Friends(Name) VALUES ('Monika')");
    19. batch.add("INSERT INTO Friends(Name) VALUES ('Tom')");
    20. batch.add("INSERT INTO Friends(Name) VALUES ('Jane')");
    21. batch.add("INSERT INTO Friends(Name) VALUES ('Robert')");
    22. batch.execute();
    23. }
    24. });
    25. }
    26. }

    该示例将批处理操作置于事务中。由于 MYSQL 中 DDL 语句的隐式提交,只有 INSERT 语句处于全有或全无模式。

    1. dbi.inTransaction(new VoidTransactionCallback() {
    2. @Override
    3. protected void execute(Handle handle, TransactionStatus status)
    4. throws Exception {
    5. ...
    6. }
    7. });

    使用该inTransaction()方法创建事务。这VoidTransactionCallback 是一个不返回值的事务回调。

    SQL 对象 API

    SQL 对象 API 为常见的 JDBI 操作提供了一种声明机制。要使用 SQL 对象 API,我们创建一个带有注释的接口或抽象类,例如@SqlQuery@SqlUpdate

    简单的例子

    我们创建一个示例,我们将在其中使用 SQL 对象 API 创建简单查询。

    1. <dependency>
    2. <groupId>org.projectlombokgroupId>
    3. <artifactId>lombokartifactId>
    4. <version>1.16.8version>
    5. dependency>

    在示例中,我们还使用了lombok库,它减少了一些样板代码。

    Car.java
    1. package com.zetcode;
    2. import lombok.Data;
    3. @Data
    4. public class Car {
    5. private final Long Id;
    6. private final String Name;
    7. private final int Price;
    8. }

    该类Car使用 lombok 的@Data 注释进行装饰。它将自动创建 getter 和 setter 方法、 equals()方法、toString()方法、 hashCode()方法和参数构造函数。

    CarMapper.java
    1. package com.zetcode;
    2. import java.sql.ResultSet;
    3. import java.sql.SQLException;
    4. import org.skife.jdbi.v2.StatementContext;
    5. import org.skife.jdbi.v2.tweak.ResultSetMapper;
    6. public class CarMapper implements ResultSetMapper {
    7. @Override
    8. public Car map(int idx, ResultSet rs, StatementContext ctx) throws SQLException {
    9. return new Car(rs.getLong("Id"), rs.getString("Name"), rs.getInt("Price"));
    10. }
    11. }

    CarMapper结果集映射到Car类。

    MyDAO.java
    1. package com.zetcode;
    2. import org.skife.jdbi.v2.sqlobject.Bind;
    3. import org.skife.jdbi.v2.sqlobject.SqlQuery;
    4. import org.skife.jdbi.v2.sqlobject.customizers.Mapper;
    5. public interface MyDAO {
    6. @SqlQuery("SELECT * FROM Cars WHERE Id = :id")
    7. @Mapper(CarMapper.class)
    8. Car findById(@Bind("id") int id);
    9. @SqlQuery("SELECT COUNT(Id) FROM Cars")
    10. int countCars();
    11. }

    这里我们有一个MyDAO装饰有两个 @SqlQuery注解的界面。这些方法通过 ID 查找汽车并计算表中的所有汽车。

    @SqlQuery("SELECT * FROM Cars WHERE Id = :id")
    

    @SqlQuery注解表示该方法执行指定的查询 。

    @Mapper(CarMapper.class)
    

    @Mapper指定查询方法上的结果集映射器 。

    Car findById(@Bind("id") int id);
    

    注释将@Bind方法的参数绑定到 SQL 查询参数。

    JDBIEx8.java
    1. package com.zetcode;
    2. import org.skife.jdbi.v2.DBI;
    3. public class JDBIEx8 {
    4. public static void main(String[] args) {
    5. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    6. "testuser", "test623");
    7. int id = 3;
    8. MyDAO dao = dbi.onDemand(MyDAO.class);
    9. Car car = dao.findById(id);
    10. System.out.println(car);
    11. int nCars = dao.countCars();
    12. System.out.printf("There are %d cars in the table", nCars);
    13. }
    14. }

    在此客户端应用程序中,我们找到 ID 等于 3 的汽车,并计算表中的所有汽车。

    MyDAO dao = dbi.onDemand(MyDAO.class);
    

    onDemand()方法创建一个新的 sql 对象,该对象将根据需要和可以分别从该 dbi 实例获取和释放连接。我们不应该显式关闭这个 sql 对象。

    Car car = dao.findById(id);
    

    我们得到一辆具有指定 ID 的汽车。

    int nCars = dao.countCars();
    

    我们计算数据库表中的汽车数量。

    事务

    在 SQL Object API 中,我们可以使用@Transaction注解来创建事务。

    authors_books.sql
    1. CREATE TABLE IF NOT EXISTS Authors(Id BIGINT PRIMARY KEY AUTO_INCREMENT,
    2. Name VARCHAR(25)) ENGINE=InnoDB;
    3. CREATE TABLE IF NOT EXISTS Books(Id BIGINT PRIMARY KEY AUTO_INCREMENT,
    4. AuthorId BIGINT, Title VARCHAR(100),
    5. FOREIGN KEY(AuthorId) REFERENCES Authors(Id) ON DELETE CASCADE)
    6. ENGINE=InnoDB;

    对于此示例,我们创建两个表:AuthorsBooks.

    MyDAO.java
    1. package com.zetcode;
    2. import java.util.List;
    3. import org.skife.jdbi.v2.exceptions.TransactionFailedException;
    4. import org.skife.jdbi.v2.sqlobject.Bind;
    5. import org.skife.jdbi.v2.sqlobject.SqlQuery;
    6. import org.skife.jdbi.v2.sqlobject.SqlUpdate;
    7. import org.skife.jdbi.v2.sqlobject.Transaction;
    8. public abstract class MyDAO {
    9. @SqlUpdate("INSERT INTO Authors(Name) VALUES(:author)")
    10. public abstract void createAuthor(@Bind("author") String author);
    11. @SqlQuery("SELECT Id FROM Authors WHERE Name = :name")
    12. abstract long getAuthorId(@Bind("name") String name);
    13. @SqlUpdate("INSERT INTO Books(AuthorId, Title) VALUES(:authorId, :title)")
    14. abstract void insertBook(@Bind("authorId") Long authorId, @Bind("title") String title);
    15. @Transaction
    16. public void insertBooksForAuthor(String author, List titles) {
    17. Long authorId = getAuthorId(author);
    18. if (authorId == null) {
    19. throw new TransactionFailedException("No author found");
    20. }
    21. for (String title : titles) {
    22. insertBook(authorId, title);
    23. }
    24. }
    25. }

    我们有一个抽象MyDAO类,我们在其中使用@SqlUpdate@SqlQuery@Transaction注释。

    1. @SqlUpdate("INSERT INTO Authors(Name) VALUES(:author)")
    2. public abstract void createAuthor(@Bind("author") String author);

    此方法添加了一个新作者。

    1. @SqlQuery("SELECT Id FROM Authors WHERE Name = :name")
    2. abstract long getAuthorId(@Bind("name") String name);

    getAuthorId()用于获取作者的 ID 。Books当我们向表中 插入新书时,需要该 ID 。

    1. @SqlUpdate("INSERT INTO Books(AuthorId, Title) VALUES(:authorId, :title)")
    2. abstract void insertBook(@Bind("authorId") Long authorId, @Bind("title") String title);

    这些insertBook()方法将一本书插入到Books 表中。

    1. @Transaction
    2. public void insertBooksForAuthor(String author, List titles) {
    3. Long authorId = getAuthorId(author);
    4. if (authorId == null) {
    5. throw new TransactionFailedException("No author found");
    6. }
    7. for (String title : titles) {
    8. insertBook(authorId, title);
    9. }
    10. }

    @Transaction注释导致 在insertBooksForAuthor() 事务中运行。所以要么所有的书都被插入,要么没有。

    JDBIEx9.java
    1. package com.zetcode;
    2. import java.util.ArrayList;
    3. import java.util.HashMap;
    4. import java.util.List;
    5. import java.util.Map;
    6. import java.util.Set;
    7. import org.skife.jdbi.v2.DBI;
    8. public class JDBIEx9 {
    9. public static void main(String[] args) {
    10. DBI dbi = new DBI("jdbc:mysql://localhost:3306/testdb",
    11. "testuser", "test623");
    12. List>> authorsBooks = new ArrayList<>();
    13. Map> autMap1 = new HashMap<>();
    14. List books1 = new ArrayList<>();
    15. books1.add("Call of the Wild");
    16. books1.add("Martin Eden");
    17. books1.add("The Iron Heel");
    18. books1.add("White Fang");
    19. autMap1.put("Jack London", books1);
    20. Map> autMap2 = new HashMap<>();
    21. List books2 = new ArrayList<>();
    22. books2.add("Father Goriot");
    23. books2.add("Colonel Chabert");
    24. books2.add("Cousing Pons");
    25. autMap2.put("Honore de Balzac", books2);
    26. authorsBooks.add(autMap1);
    27. authorsBooks.add(autMap2);
    28. MyDAO dao = dbi.onDemand(MyDAO.class);
    29. for (Map> map : authorsBooks) {
    30. Set ks = map.keySet();
    31. for (String author : ks) {
    32. dao.createAuthor(author);
    33. List titles = map.get(author);
    34. dao.insertBooksForAuthor(author, titles);
    35. }
    36. }
    37. }
    38. }

    该示例将两位作者及其书籍插入数据库。

    在本教程中,我们介绍了 JDBI 库。

  • 相关阅读:
    011:获取上证50的所有股票代码,并下载各个股K线数到excel表中
    MyBatis基本操作及SpringBoot单元测试
    LC926. 将字符串翻转到单调递增(JAVA - 动态规划)
    java毕业设计电影订票系统Mybatis+系统+数据库+调试部署
    11.ElasticSearch系列之搜索相关性算分机制
    MongoDB安装及进程介绍
    npm设置国内源(淘宝镜像源),解决npm包下载速度慢的问题
    【Python入门】文件夹操作
    网络运维的重要性
    C++编程(五)单例模式 友元
  • 原文地址:https://blog.csdn.net/allway2/article/details/126907374