8.2. MyBatis基础

8.2.1. 发展

MyBatis是Java领域一款优秀的持久层框架,它来源于iBatis这个apache开源项目,2010年iBatis由apache software foundation迁移到Google Code,并更名为MyBatis。MyBatis支持自定义SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO(Plain Old Java Objects,普通老式Java对象)为数据库中的记录。(mybatis.org)

8.2.2. 特点

MyBatis具有以下特点:

  • 需要开发人员自定义SQL,适合喜欢手写SQL的人
  • 支持动态SQL,可以灵活地构造极为复杂的查询
  • 支持映射的接口绑定,与三层体系结构应用完美融合

8.2.3. 组成与执行过程

8.2.4. 第一个MyBatis程序

准备工作:数据库和实体类的创建

为了演示本章代码,首先创建数据库tmall,并创建表:

  1. CREATE TABLE `Customer` (
  2. `id` int NOT NULL AUTO_INCREMENT,
  3. `name` varchar(50) DEFAULT NULL,
  4. `mobilePhone` varchar(20) DEFAULT NULL,
  5. `birthDate` datetime DEFAULT NULL,
  6. PRIMARY KEY (`id`)
  7. ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb3;
  8. CREATE TABLE `Cart` (
  9. `id` int NOT NULL AUTO_INCREMENT,
  10. `totalPrice` float DEFAULT NULL,
  11. `customerId` int DEFAULT NULL,
  12. PRIMARY KEY (`id`)
  13. ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb3;
  14. CREATE TABLE `CartItem` (
  15. `id` int NOT NULL AUTO_INCREMENT,
  16. `name` varchar(256) DEFAULT NULL,
  17. `price` float DEFAULT NULL,
  18. `cartId` int DEFAULT NULL,
  19. PRIMARY KEY (`id`)
  20. ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb3;
  21. CREATE TABLE `Promotion` (
  22. `id` int NOT NULL AUTO_INCREMENT,
  23. `name` varchar(256) DEFAULT NULL,
  24. `discount` float DEFAULT NULL,
  25. PRIMARY KEY (`id`)
  26. ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb3;
  27. CREATE TABLE `CustomerPromotion` (
  28. `id` int NOT NULL AUTO_INCREMENT,
  29. `customerId` int DEFAULT NULL,
  30. `promotionId` int DEFAULT NULL,
  31. PRIMARY KEY (`id`)
  32. ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb3;

与数据库表相对应的,建立实体类:

  1. public class Customer {
  2. private int id;
  3. private String name;
  4. private String mobilePhone;
  5. private LocalDate birthDate;
  6. private Cart cart;
  7. private List<Promotion> promotions = new ArrayList<>();
  8. // getters and setters
  9. // ...
  10. }
  1. public class Cart {
  2. private int id;
  3. private float totalPrice;
  4. private int customerId;
  5. private List<CartItem> cartItems = new ArrayList<>();
  6. // getters and setters
  7. // ...
  8. }
  1. public class CartItem {
  2. private int id;
  3. private String name;
  4. private float price;
  5. // getters and setters
  6. // ...
  7. }
  1. public class Promotion {
  2. private int id;
  3. private String name;
  4. private float discount;
  5. private List<Customer> customers = new ArrayList<>();
  6. // getters and setters
  7. // ...
  8. }

这里需要注意的是,在数据库中可能存在表之间的关联,根据不同情况,实体类中有不同的做法。

  • 表之间的一对一关系:在数据库中通常通过主键-外键的方式来关联。在实体类中可以通过类之间的组合/聚合关系来表示,也就是可以在类中声明对象类型属性。如上例中的Customer类和Cart类。
  • 表之间的一对多关系:在数据库中通常也通过主键-外键方式来关联。在实体类中可以在类中声明对象的集合类型的属性。如上例中的Cart类和CartItem类。
  • 表之间的多对多关系:在数据库中通常需要建立关联表。在实体类中可以在关联的两个类中互相声明对方的对象的集合类型属性。如上例中的Customer类和Promotion类。

有一些ORM框架,只需要创建数据库或实体类,它可以根据数据库自动生成实体类(Database First),或根据实体类自动创建数据库表(Model First)。MyBatis不行,都需要手工创建。

使用MyBatis的步骤

第一步,配置pom.xml的依赖项(或下载并导入jar包)

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>3.5.7</version>
  5. </dependency>
  6. <!--mysql驱动程序-->
  7. <dependency>
  8. <groupId>mysql</groupId>
  9. <artifactId>mysql-connector-java</artifactId>
  10. <version>8.0.27</version>
  11. </dependency>
  12. <!-- log4j,用于在控制台输出生成的SQL语句 -->
  13. <!-- 此处不能使用最新的log4j.core,与mybatis不兼容 -->
  14. <!-- MyBatis还支持其它多种日志组件,但官方文档中以log4j为例,所以大家都用log4j -->
  15. <dependency>
  16. <groupId>log4j</groupId>
  17. <artifactId>log4j</artifactId>
  18. <version>1.2.17</version>
  19. </dependency>

第二步,在Resources路径下建立MyBatis核心配置文件(也可以不使用xml进行配置,而是通过编码的方式进行设置)

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <settings>
  7. <!--配置mybatis使用的日志组件,关于settings中可以进行的其它配置,详见文档-->
  8. <setting name="logImpl" value="LOG4J"/>
  9. </settings>
  10. <environments default="development">
  11. <environment id="development">
  12. <transactionManager type="JDBC"/>
  13. <dataSource type="POOLED">
  14. <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
  15. <property name="url" value="jdbc:mysql://localhost:3306/tmall?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
  16. <property name="username" value="root"/>
  17. <property name="password" value="hrbust123"/>
  18. </dataSource>
  19. </environment>
  20. </environments>
  21. <mappers>
  22. <!--如果与当前文件在同一路径下,可以不写路径-->
  23. <mapper resource="CustomerMapper.xml"/>
  24. </mappers>
  25. </configuration>

相应的log4j.properties文件(放在resources目录下)

  1. # 全局日志配置
  2. log4j.rootLogger=ERROR, stdout
  3. # MyBatis 日志配置
  4. log4j.logger.org.hrbust.tmall.mapper=DEBUG
  5. # 控制台输出
  6. log4j.appender.stdout=org.apache.log4j.ConsoleAppender
  7. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
  8. log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

第三步,建立MyBatis的映射文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--namespace属性必须要有,给mapper起个名字-->
  6. <mapper namespace="org.hrbust.tmall.mapper.CustomerMapper">
  7. <select id="getCustomers" resultType="org.hrbust.tmall.entity.Customer">
  8. select * from Customer
  9. </select>
  10. <select id="getCustomerById" parameterType="Integer" resultType="org.hrbust.tmall.entity.Customer">
  11. select * from Customer where id=#{id}
  12. </select>
  13. </mapper>

第四步,测试

  1. public class Main {
  2. public static void main(String args[]) throws IOException {
  3. // Step 1: 获取核心配置文件
  4. String resource = "mybatis-config.xml";
  5. // 这句话会抛出IOException,正常应该捕获异常,此处简单处理,声明main函数抛出异常
  6. InputStream inputStream = Resources.getResourceAsStream(resource);
  7. // Step 2: 通过builder得到SqlSessionFactory的实例
  8. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  9. // Step 3: 打开Session
  10. SqlSession session = sqlSessionFactory.openSession();
  11. // Step 4: 执行数据库操作
  12. //Customer customer = session.selectOne("getCustomerById", 2);
  13. List<Customer> customers = session.selectList("getCustomers");
  14. // Step 5: 关闭Session
  15. session.close();
  16. System.out.println(customers);
  17. }
  18. }

运行程序,可以发现成功检索出了数据库中的数据。刚才在演示ORM原理的时候,我们通过手工的方式让数据库表的字段名和实体对象的属性名相对应。但在上面的例子中,使用MyBatis时我们却没有做过这件事,显然这件事是必须要做的,那么MyBatis是如何知道对象的属性与数据库表的哪个字段对应的?