Mybatis 框架学习

Mybatis

一. 入门

1. JDBC 回顾

(1). 准备数据库

  • 新建 mybatis_learn 数据库
  • 执行 sql 脚本
     1 -- ----------------------------
     2 -- Table structure for `Blog`
     3 -- ----------------------------
     4 DROP TABLE IF EXISTS `Blog`;
     5 CREATE TABLE `Blog` (
     6   `id` int(11) NOT NULL AUTO_INCREMENT,
     7   `author` varchar(128) NOT NULL COMMENT ‘作者‘,
     8   `title` varchar(128) NOT NULL COMMENT ‘博客标题‘,
     9   PRIMARY KEY (`id`)
    10 ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
    11 ?
    12 -- ----------------------------
    13 -- Records of Blog
    14 -- ----------------------------
    15 INSERT INTO `Blog` VALUES (‘1‘, ‘张三‘, ‘Java基础概述‘);
    16 INSERT INTO `Blog` VALUES (‘2‘, ‘李四‘, ‘面向对象概述‘);
    17 INSERT INTO `Blog` VALUES (‘3‘, ‘王五‘, ‘什么框架‘);

(2). 原生 JDBC 编程步骤

  1. 加载数据库驱动
  2. 创建并获取数据库链接
  3. 设置 sql 语句
  4. 创建 JDBC Statement对象
  5. 设置 sql 语句中的参数(使用PreparedStatement)
  6. 通过 Statement 执行 sql 并获取结果
  7. 对 sql 执行结果进行解析处理
  8. 释放资源(ResultSet、Preparedstatement、Connection)

(3). 原生 JDBC 程序

 1 package com.richer.jdbc;
 2 ?
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.PreparedStatement;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 ?
 9 public class JDBCTest {
10 ?
11     public static void main(String[] args) {
12         Connection connection = null;
13         PreparedStatement preparedStatement = null;
14         ResultSet resultSet = null;
15 ?
16         try {
17             // 1、加载数据库驱动
18             Class.forName("com.mysql.jdbc.Driver");
19 ?
20             // 2、获取数据库链接
21             /**
22              * 问题1:频繁获取释放数据库连接影响数据库性能
23              * 解决:数据库连接池,C3P0 DBCP DRUID(德鲁伊,阿里巴巴出品)
24              */
25             connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis_learn?characterEncoding=utf-8", "root", "root");
26             // 3、定义sql语句 ?表示占位符
27             /**
28              * 问题2:sql语句硬编码,后期难以维护
29              * 如果sql语句和java代码分离,比如放到配置文件当中。mybatis就是这么干的
30              */
31             String sql = "select * from blog where author = ?";
32             // 4、获取预处理statement
33             preparedStatement = connection.prepareStatement(sql);
34             // 5、设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
35             /**
36              * 问题3:参数和占位符一一对应,sql语句where条件发生变化,修改java代码,后期难以维护
37              */
38             preparedStatement.setString(1, "张三");
39             // 6、向数据库发出sql执行查询,查询出结果集
40             resultSet = preparedStatement.executeQuery();
41             // 7、解析处理结果集
42             /**
43              * 问题4:解析麻烦,查询列硬编码
44              * 期望,如果单条记录,给我对象,如果多条记录,给我对象集合
45              */
46             while (resultSet.next()) {
47                 System.out.println(resultSet.getString("id") + "  " + resultSet.getString("author"));
48             }
49         } catch (Exception e) {
50             e.printStackTrace();
51         } finally {
52             // 8、释放资源
53             if (resultSet != null) {
54                 try {
55                     resultSet.close();
56                 } catch (SQLException e) {
57                     e.printStackTrace();
58                 }
59             }
60             if (preparedStatement != null) {
61                 try {
62                     preparedStatement.close();
63                 } catch (SQLException e) {
64                     e.printStackTrace();
65                 }
66             }
67             if (connection != null) {
68                 try {
69                     connection.close();
70                 } catch (SQLException e) {
71                     e.printStackTrace();
72                 }
73             }
74         }
75     }
76 }

(4). 原生 JDBC 问题总结

  1. 频繁创建、释放数据库连接造成系统资源浪费,影响系统性能。使用数据库连接池技术可以解决此问题。
  2. sql 语句写在代码中造成代码不易维护,实际应用中 sql 变化的可能较大,sql 变动需要改变 java 代码。
  3. 向 sql 语句传参数麻烦,因为 sql 语句的 where 条件不一定,可能多也可能少,占位符需要和参数一一对应。
  4. 对结果集解析麻烦(列名硬编码),Sql变化会导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 Pojo 对象解析比较方便。

2. Mybatis 介绍及架构原理

(1) Mybatis 介绍

Mybatis 是一个持久层框架,它的前身是由 Apache 管理的一个顶级项目叫 ibatis,但是在2010年后该项目交给 Google code 管理,改名为 Mybatis,并在2013年迁移到 Github 上。

Mybatis 在 ibatis 的基础上做了一些封装及优化。比如通过 Mapper 动态代理的方式开发 Dao 等。

Mybatis 的特点是使用 Xml 文件来配置 sql 语句。程序员自己写 sql 语句,当需求变化时我们只需要修改配置文件即可,比较灵活。

另外,Mybatis 向 sql 语句传参可以直接传入 java 对象,不必参数和占位符一一对应;把查询到的结果集映射为 java 对象。

(2). Hibernate 架构回顾

(3) Mybatis 架构

Mybatis配置

  • 全局配置文件 SqlMapConfig.xml,配置了 Mybatis 的运行环境等信息。Mapper.xml 文件即 sql 映射文件,文件中配置了操作数据库的 sql 语句。此文件需要在 SqlMapConfig.xml 中加载。
  • 通过 Mybatis 环境等配置信息构造 SqlSessionFactory,即会话工厂。
  • 由会话工厂创建 SqlSession 即会话,操作数据库需要通过 SqlSession 进行。
  • Mybatis 底层自定义了 Executor 执行器接口操作数据库,Executor 执行器调用具体的MappedStatement 对象执行数据库操作动作。
  • MappedStatement 也是 Mybatis 一个底层封装对象,它包装了 Mybatis 配置信息及 sql 映射信息等。Mapper.xml 文件中一个 sql 对应一个 Mapped Statement 对象,sql 的 id 即是 Mapped statement 的id。
  • Executor 通过 MappedStatement 在执 sql 前将输入的 java 对象映射至 sql 中,输入参数映射的意思就是 JDBC 编程中对 PreparedStatement 设置参数。Executor 通过 MappedStatement 在执行 sql 后将输出结果映射至 java 对象中,输出结果映射过程相当于 jdbc 编程中对结果的解析处理过程。

(4) Mybatis 与 Hibernate 的区别

越来越多的企业在用Mybatis,它的市场占有率越来越高。与之相比,Hibernate的市场占有率却在走低

  1. Hibernate 是一个完全的 ORM 框架,Mybatis 是一个不完全的 ORM 框架

    Hibernate 自动化程度高,只需配置 OR 映射关系,不需要写 Sql 语句,怎么执行由框架底层控制。

    Mybatis 虽然将 Sql 与 Java 对象做了关系映射,但需要程序员自己写 Sql。

  2. Hibernate 学习门槛高,Mybatis 学习门槛较低

    Hibernate 学习门槛高,精通门槛更高,设计 O/R 映射和 Hibernate 调优都需要很强的经验和能力。

    Mybatis 比较容易上手和掌握,重点关注 Sql 语句即可;

  3. Hibernate 灵活度差但数据库无关性好,Mybatis 灵活度高,但牺牲了数据库无关性

    Hibernate 不能干预具体 Sql 的执行,但数据库无关性好,切换不同数据库时只需要切换数据库类型即可。

    Mybatis 可严格控制 Sql 的执行性能,灵活度高,适合于软件的需求变化快而且多的软件,但灵活的前提是牺牲了数据库的无关性,如果要实现支持多种数据库的软件则需要自定义多套 Sql 映射文件,工作量大。

选型原则

  总之,满足需求的前提下,只要做出维护性、扩展性好的软件架构都是好架构,框架只有合适的才是最好的。

选型建议

  访问量小性能要求不高的内网项目,推荐使用全自动的 Hibernate 框架,可以提高开发效率。

  访问量大性能要求高的内网或者互联网项目,推荐使用 Mybatis 框架。

3. 第一个 Mybatis 程序

(1). 引入资源 pom.xml

 1 <dependencies>
 2     <!-- junit -->
 3     <dependency>
 4         <groupId>junit</groupId>
 5         <artifactId>junit</artifactId>
 6         <version>4.12</version>
 7         <scope>test</scope>
 8     </dependency>
 9     <!-- mybatis -->
10     <dependency>
11         <groupId>org.mybatis</groupId>
12         <artifactId>mybatis</artifactId>
13         <version>3.2.7</version>
14     </dependency>
15     <!-- mysql 驱动 -->
16     <dependency>
17         <groupId>mysql</groupId>
18         <artifactId>mysql-connector-java</artifactId>
19         <version>5.1.46</version>
20     </dependency>
21     <!-- log4j -->
22     <dependency>
23         <groupId>log4j</groupId>
24         <artifactId>log4j</artifactId>
25         <version>1.2.17</version>
26     </dependency>
27 </dependencies>

(2). 创建 pojo

 1 package com.richer.mybatis.pojo;
 2 ?
 3 public class Blog {
 4     private int id;
 5     private String author;
 6     private String title;
 7 ?
 8     public int getId() {
 9         return id;
10     }
11 ?
12     public void setId(int id) {
13         this.id = id;
14     }
15 ?
16     public String getAuthor() {
17         return author;
18     }
19 ?
20     public void setAuthor(String author) {
21         this.author = author;
22     }
23 ?
24     public String getTitle() {
25         return title;
26     }
27 ?
28     public void setTitle(String title) {
29         this.title = title;
30     }
31 ?
32     @Override
33     public String toString() {
34         return "Blog [id=" + id + ", author=" + author + ", title=" + title + "]";
35     }
36 }
 

(3). 创建 SqlMapConfig.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     <environments default="development">
 7         <environment id="development">
 8             <transactionManager type="JDBC" />
 9             <dataSource type="POOLED">
10                 <property name="driver" value="com.mysql.jdbc.Driver" />
11                 <property name="url"
12                           value="jdbc:mysql://localhost:3306/mybatis_learn?characterEncoding=utf-8" />
13                 <property name="username" value="root" />
14                 <property name="password" value="root" />
15             </dataSource>
16         </environment>
17     </environments>
18     <mappers>
19         <mapper resource="sqlmap/BlogMapper.xml" />
20     </mappers>
21 </configuration>

(4). 创建 BlogMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
    <select id="queryBlogById" parameterType="Integer"
            resultType="com.richer.mybatis.pojo.Blog">
        select * from blog where id=#{id}
    </select>
</mapper>

(5). 引入日志配置文件

1 # Global logging configuration
2 log4j.rootLogger=DEBUG, stdout
3 # Console output...
4 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

(6). 创建测试类

 1 public class TestQuickStart {
 2     @Test
 3     public void testQueryBlogById() throws Exception {
 4         // 1. 加载SqlMapConfig.xml配置文件
 5         InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 6         // 2. 创建SqlSessionFactoryBuilder对象
 7         SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
 8         // 3. 创建SqlSessionFactory对象
 9         SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
10         // 4. 创建SqlSession对象
11         SqlSession sqlSession = sqlSessionFactory.openSession();
12         // 5. 执行SqlSession对象执行查询,获取结果Blog
13         // 第一个参数是BlogMapper.xml的statement的id,第二个参数是执行sql需要的参数;
14         Blog blog = sqlSession.selectOne("queryBlogById", 1);
15         // 6. 打印结果
16         System.out.println(blog);
17         // 7. 释放资源
18         sqlSession.close();
19     }
20 }

4.Mybatis 入门详解

(1).准备数据库

  • 使用数据库 mybatis_learn
  • 执行 sql 脚本
     1 -- ----------------------------
     2 -- Table structure for `user`
     3 -- ----------------------------
     4 DROP TABLE IF EXISTS `user`;
     5 CREATE TABLE `user` (
     6   `id` int(11) NOT NULL AUTO_INCREMENT,
     7   `username` varchar(32) NOT NULL COMMENT ‘用户名称‘,
     8   `birthday` date DEFAULT NULL COMMENT ‘生日‘,
     9   `sex` char(1) DEFAULT NULL COMMENT ‘性别‘,
    10   `address` varchar(256) DEFAULT NULL COMMENT ‘地址‘,
    11   PRIMARY KEY (`id`)
    12 ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
    13 ?
    14 -- ----------------------------
    15 -- Records of user
    16 -- ----------------------------
    17 INSERT INTO `user` VALUES (‘1‘, ‘王五‘, null, ‘2‘, null);
    18 INSERT INTO `user` VALUES (‘10‘, ‘张三‘, ‘2014-07-10‘, ‘1‘, ‘北京市‘);
    19 INSERT INTO `user` VALUES (‘16‘, ‘张小明‘, null, ‘1‘, ‘河南郑州‘);
    20 INSERT INTO `user` VALUES (‘22‘, ‘陈小明‘, null, ‘1‘, ‘河南郑州‘);
    21 INSERT INTO `user` VALUES (‘24‘, ‘张三丰‘, null, ‘1‘, ‘河南郑州‘);
    22 INSERT INTO `user` VALUES (‘25‘, ‘陈小明‘, null, ‘1‘, ‘河南郑州‘);
    23 INSERT INTO `user` VALUES (‘26‘, ‘王五‘, null, null, null);

(2). 需求1 : 根据用户 id 查询一个用户

i. 创建 pojo
 1 public class User{
 2 ?
 3     private int id;
 4     private String username;
 5     private String sex;
 6     private Date birthday;
 7     private String address;
 8 ?
 9     public int getId() {
10         return id;
11     }
12     public void setId(int id) {
13         this.id = id;
14     }
15     public String getUsername() {
16         return username;
17     }
18     public void setUsername(String username) {
19         this.username = username;
20     }
21     public String getSex() {
22         return sex;
23     }
24     public void setSex(String sex) {
25         this.sex = sex;
26     }
27     public Date getBirthday() {
28         return birthday;
29     }
30     public void setBirthday(Date birthday) {
31         this.birthday = birthday;
32     }
33     public String getAddress() {
34         return address;
35     }
36     public void setAddress(String address) {
37         this.address = address;
38     }
39     @Override
40     public String toString() {
41         return "User [id=" + id + ", username=" + username + ", sex=" + sex
42             + ", birthday=" + birthday + ", address=" + address + "]";
43     }
44 }
ii.创建 SqlMapConfig.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 <!-- 配置 -->
 6 <configuration>
 7     <!--
 8   environments 配置数据源环境
 9   可以配置多个 environment
10   default : 默认使用哪个数据源,配置对应的 id
11  -->
12     <environments default="development">
13         <!-- 开发用数据源 -->
14         <environment id="development">
15             <!--
16     transactionManager:事务管理器
17     type = "JDBC" : 使用 JDBC 事务管理机制
18     type = "MANAGERED" : mybatis 不管理事务,交给外部框架
19    -->
20             <transactionManager type="JDBC" />
21             <!--
22     POOLED : 使用连接池
23     UNPOOLED : 不使用连接池
24     -->
25             <dataSource type="POOLED">
26                 <property name="driver" value="com.mysql.jdbc.Driver" />
27                 <property name="url"
28                           value="jdbc:mysql://localhost:3306/mybatis_learn?characterEncoding=utf-8" />
29                 <property name="username" value="root" />
30                 <property name="password" value="root" />
31             </dataSource>
32         </environment>
33         <!-- 测试用数据源 -->
34         <environment id="test">
35             <transactionManager type="JDBC" />
36             <dataSource type="POOLED">
37                 <property name="driver" value="com.mysql.jdbc.Driver" />
38                 <property name="url"
39                           value="jdbc:mysql://localhost:3306/mybatis_learn?characterEncoding=utf-8" />
40                 <property name="username" value="root" />
41                 <property name="password" value="root" />
42             </dataSource>
43         </environment>
44         <!-- 生产用数据源 -->
45         <environment id="produce">
46             <transactionManager type="JDBC" />
47             <dataSource type="POOLED">
48                 <property name="driver" value="com.mysql.jdbc.Driver" />
49                 <property name="url"
50                           value="jdbc:mysql://localhost:3306/mybatis_learn?characterEncoding=utf-8" />
51                 <property name="username" value="root" />
52                 <property name="password" value="root" />
53             </dataSource>
54         </environment>
55     </environments>
56     <!-- 加载 sql 映射文件 -->
57     <mappers>
58         <!-- resource 加载 classpath 下指定的 sql 映射文件 -->
59         <mapper resource="sqlmap/UserMapper.xml" />
60     </mappers>
61 </configuration>
iii. 创建 UserMapper.xml
 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 <!--
 6  映射,存放 sql 语句
 7  namespace : 分类管理 sql 语句
 8  唯一确定 sql 语句 : namespace + "." + id
 9 -->
10 <mapper namespace="test">
11     <!--
12    查询使用 select 标签
13    id : sql 语句标识符,通常也称为 statement 的 id
14   parameterType : 参数类型(输入映射)
15   resultType : 结果类型(输出映射),配置为 pojo 那么 Mybatis 就把结果集中的每一条记录封装为指定的 pojo
16   -->
17     <select id="queryUserById" parameterType="Integer"
18             resultType="com.richer.mybatis.pojo.User">
19         <!--
20    #{} 固定取参语法
21    #{} 取参名称 : parameterType 为基础数据类型时,名称任意
22                 parameterType 为 pojo 时,名称为属性名
23    #{} 预编译语句 防止 sql 注入
24    -->
25         select * from user where id=#{id}
26     </select>
27 </mapper>
iv.创建测试类
 1 /**
 2      * 测试用例 : 根据 id 查询用户
 3      * @throws IOException
 4      */
 5 @Test
 6 public void testQueryUserByID() throws IOException{
 7     // 读取配置文件
 8     InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 9     // 获取会话工厂
10     SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
11     // 获取会话
12     SqlSession sqlSession = sessionFactory.openSession();
13     /**
14          * 调用 sqlSession 的 api
15          * param1 : sql 语句的唯一标识符
16          * param2 : 传入的参数
17          */
18     User user = sqlSession.selectOne("test.queryUserById",16);
19     System.out.println(user);
20     sqlSession.close();
21 }

(3).需求2 : 根据 username 模糊查询用户列表

i. #{ } 取参
UserMapper.xml
<!-- resultType : 返回多条记录时配置和单条一样,mybatis 会自动吧多条数据放到集合里 -->
<select id="queryUserByUsername" parameterType="String"
        resultType="com.richer.mybatis.pojo.User">
    select * from user where username like #{username}
</select>
测试类
 1 /**
 2      * 测试用例 : 根据 username 模糊查询用户列表
 3      * @throws IOException
 4      */
 5 @Test
 6 public void testQueryUserByUsername() throws IOException{
 7     // 读取配置文件
 8     InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 9     // 获取会话工厂
10     SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
11     // 获取会话
12     SqlSession sqlSession = sessionFactory.openSession();
13     /**
14          * 调用 sqlSession 的 api
15          * param1 : sql 语句的唯一标识符
16          * param2 : 传入的参数
17          */
18     //注意 : 多条数据使用 selectOne 会报异常 TooManyResultsException
19     List<User> list = sqlSession.selectList("test.queryUserByUsername","%王%");
20     if (list != null && list.size() > 0) {
21         for(User user : list){
22             System.out.println(user);
23         }
24     }
25     sqlSession.close();
26 }

ii.${ }取参

UserMapper.xml
 1 <select id="queryUserByUsername2" parameterType="String"
 2         resultType="com.richer.mybatis.pojo.User">
 3     <!--
 4    $()固定取参语法
 5    $()取参名称 : parameterType 为基础数据类型时,名称必须为 value
 6                parameterType 为 pojo 时,名称为属性名
 7    $()不会添加单引号对
 8    $()原理:简单的字符串拼接
 9   -->
10     select * from user where username like ${value}
11 </select>
测试类
 1 /**
 2      * 测试用例 : 根据 username 模糊查询用户列表2
 3      * @throws IOException
 4      */
 5 @Test
 6 public void testQueryUserByUsername2() throws IOException{
 7     // 读取配置文件
 8     InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 9     // 获取会话工厂
10     SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
11     // 获取会话
12     SqlSession sqlSession = sessionFactory.openSession();
13     /**
14          * 调用 sqlSession 的 api
15          * param1 : sql 语句的唯一标识符
16          * param2 : 传入的参数
17          */
18     List<User> list = sqlSession.selectList("test.queryUserByUsername2","‘%王%‘");
19     if (list != null && list.size() > 0) {
20         for(User user : list){
21             System.out.println(user);
22         }
23     }
24     sqlSession.close();
25 }

iii.#{ }与${ }取参原则

一般使用 #{ } ,当传入参数为数据库对象使用 ${ }(比如表名)

(4). 需求3 : 保存用户

i.UserMapper.xml
1 <insert id="saveUser" parameterType="com.richer.mybatis.pojo.User" >
2     insert into user(username,sex,birthday,address)
3     values(#{username},#{sex},#{birthday},#{address})
4 </insert>
ii.测试类
 1 /**
 2      * 测试用例 : 保存用户
 3      * @throws IOException
 4      */
 5     @Test
 6     public void testSaveUser() throws IOException{
 7         // 读取配置文件
 8         InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 9         // 获取会话工厂
10         SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
11         // 获取会话
12         SqlSession sqlSession = sessionFactory.openSession();
13         User user = new User();
14         user.setUsername("妲己");
15         user.setSex("2");
16         user.setBirthday(new Date());
17         user.setAddress("朝歌");
18         sqlSession.insert("test.saveUser",user);
19         //增加删除修改需要提交事务,底层是 connection 的事务机制
20         sqlSession.commit();
21         sqlSession.close();
22     }
iii.返回 mysql 自增主键 id (解决输出 id=0 的问题)
UserMapper.xml
 1 <insert id="saveUser" parameterType="com.richer.mybatis.pojo.User" >
 2     <!--
 3    selectKey : 查询主键标签
 4    order : 查询主键语句在 insert 之前还是之后
 5    resultType : 查询出来的主键要回显的属性值
 6    -->
 7     <selectKey order="AFTER" resultType="Integer" keyProperty="id">
 8         获取最后一个自增 id
 9         select last_insert_id()
10     </selectKey>
11     insert into user(username,sex,birthday,address)
12     values(#{username},#{sex},#{birthday},#{address})
13 </insert>

(5). 需求4 : 更新和删除用户

i. 更新用户
UserMapper.xml
1 <update id="updateUserById" parameterType="com.richer.mybatis.pojo.User">
2     update user set username = #{username} where id = #{id}
3 </update>
测试类
 1 /**
 2      * 测试用例 : 根据 id 修改用户
 3      * @throws IOException
 4      */
 5 @Test
 6 public void testUpdateUserById() throws IOException{
 7     // 读取配置文件
 8     InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 9     // 获取会话工厂
10     SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
11     // 获取会话
12     SqlSession sqlSession = sessionFactory.openSession();
13     User user = new User();
14     user.setUsername("比干");
15     user.setId(31);
16     sqlSession.update("test.updateUserById",user);
17     //增加删除修改需要提交事务,底层是 connection 的事务机制
18     sqlSession.commit();
19     System.out.println(user);
20     sqlSession.close();
21 }
ii. 删除用户
UserMapper.xml
1 <delete id="deleteUserById" parameterType="Integer">
2     delete from user where id = #{id}
3 </delete>
测试类
 1 /**
 2      * 测试用例 : 根据 id 删除用户
 3      * @throws IOException
 4      */
 5 @Test
 6 public void testDeleteUserById() throws IOException{
 7     // 读取配置文件
 8     InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 9     // 获取会话工厂
10     SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
11     // 获取会话
12     SqlSession sqlSession = sessionFactory.openSession();
13     sqlSession.delete("test.deleteUserById",28);
14     //增加删除修改需要提交事务,底层是 connection 的事务机制
15     sqlSession.commit();
16     sqlSession.close();
17 }

(6). 小结

  1. 频繁创建、释放数据库连接造成系统资源浪费,影响系统性能。使用数据库连接池技术可以解决此问题。解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库连接。
  2. Sql语句写在代码中造成代码不易维护,实际应用中Sql变化的可能较大,Sql变动需要改变java代码。

    解决:将Sql语句配置在XXXXmapper.xml文件中与Java代码分离。

  3. 向Sql语句传参数麻烦,因为Sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应(硬编码)。

    解决:Mybatis自动将Java对象映射至Sql语句,通过statement中的parameterType定义输入参数的类型。

  4. 对结果集解析麻烦(查询列硬编码),Sql变化会导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成Pojo对象解析比较方便。

    解决:Mybatis自动将Sql执行结果映射至Java对象,通过statement中的resultType定义输出结果的类型。

5. Mybatis 的 两种 Dao 开发方式

(1). 原始 Dao 开发方式

UserDao.java
1 public interface UserDao {
2     User queryUserById(int id);
3 }
UserDaoImpl.java
 1 public class UserDaoImpl implements UserDao {
 2 ?
 3     private SqlSessionFactory sqlSessionFactory;
 4 ?
 5     public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
 6         this.sqlSessionFactory = sqlSessionFactory;
 7     }
 8 ?
 9     public User queryUserById(int id) {
10         SqlSession sqlSession = sqlSessionFactory.openSession();
11         User user = sqlSession.selectOne("test.queryUserById",id);
12         sqlSession.close();
13         return user;
14     }
15 }
测试类
 1 public class Test_02 {
 2     @Test
 3     public void testQueryUserById() throws IOException{
 4         // 读取配置文件
 5         InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 6         // 获取会话工厂
 7         SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 8         UserDao userDao = new UserDaoImpl(sessionFactory);
 9         User user = userDao.queryUserById(27);
10         System.out.println(user);
11     }
12 }

(2). mapper 动态代理开发方式

i. 开发规范

Mapper动态代理开发方式只需要程序员开发 Mapper 接口(相当于 Dao 接口),Mybatis 框架会根据接口定义创建接口的动态代理对象,代理对象的方法同 Dao 接口实现类中的方法。

Mapper 接口开发需要遵循以下4个规范:

  • Mapper 映射文件中的 namespace 与 mapper 接口的类路径相同。
  • Mapper 接口方法名和 Mapper 映射文件中定义的每个 Sql 的 id 相同
  • Mapper 接口方法的输入参数类型和 Mapper 映射文件中定义的每个 Sql 的 ParameterType 的类型相同
  • Mapper 接口方法的输出参数类型和 Mapper 映射文件中定义的每个 Sql 的 resultType 的类型相同
ii. UserMapper.xml 映射文件
1 <mapper namespace="com.richer.mybatis.mapper.UserMapper">
2     <select id="queryUserById" parameterType="Integer"
3         resultType="com.richer.mybatis.pojo.User">
4         select * from user where id=#{id}
5     </select>
6 </mapper>
iii. SqlMapConfig.xml 加载 UserMapper.xml
1 <mapper resource="mapper/UserMapper.xml" />
iv. UserMapper.java 接口文件
public interface UserMapper {    User queryUserById(int id);}
v. 测试类
 1 @Test
 2 public void testQueryUserById() throws IOException {
 3     // 读取配置文件
 4     InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 5     // 获取会话工厂
 6     SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 7     SqlSession sqlSession = sessionFactory.openSession();
 8     //使用 jdk 动态代理,面向接口,实现了 InvocationHandler
 9     UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
10     User user = userMapper.queryUserById(27);
11     System.out.println(user);
12 }

6. 全局配置文件 SqlMapConfig.xml 说明

(1). 配置内容和顺序

SqlMapConfig.xml 中配置的内容和顺序如下:

  • properties 属性配置信息
  • settings 全局配置参数
  • typeAliases 类型别名
  • typeHandlers 类型处理器
  • objectFactory 对象工厂
  • plugins 插件
  • environments 环境集合属性对象
  • environment 环境子属性对象
  • transactionManager 事务管理
  • dataSource 数据源
  • mappers 映射器

注意 : 标签是有顺序的 !

(2). properties 属性配置信息

使用的 properties 的好处:配置数据共享

配置 db.properties
1 jdbc.driver=com.mysql.jdbc.Driver
2 jdbc.url=jdbc:mysql://localhost:3306/mybatis_learn?characterEncoding=utf-8
3 jdbc.username=root
4 jdbc.password=root
修改 SqlMapConfig.xml
 1 <!-- 用resource属性加载外部配置文件 -->
 2 <properties resource="db.properties">
 3     <!-- 在properties内部用property定义属性 -->
 4     <!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 -->
 5     <property name="jdbc.username" value="root111" />
 6 </properties>
 7 ?
 8 <environments default="development">
 9     <environment id="development">
10         <transactionManager type="JDBC" />
11         <dataSource type="POOLED">
12             <property name="driver" value="${jdbc.driver}" />
13             <property name="url"
14                       value="${jdbc.url}" />
15             <property name="username" value="${jdbc.username}" />
16             <property name="password" value="${jdbc.password}" />
17         </dataSource>
18     </environment>
19 </environments>

(3). typeAliases 类型别名

i. Mybatis默认支持的别名
别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map
ii. 自定义别名
SqlMapConfig.xml
1 <typeAliases>
2     <!-- 定义好的别名不区分大小写 -->
3     <!-- <typeAlias type="com.richer.mybatis.pojo.User" alias="abc"/> -->
4     <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
5     <package name="com.richer.mybatis.pojo"/>
6 </typeAliases>

(4). mappers 映射器



 1 <mappers>
 2     <!-- resource 加载 classpath 下指定的 sql 映射文件 -->
 3     <!-- <mapper resource="sqlmap/UserMapper.xml" />
 4   <mapper resource="mapper/UserMapper.xml" /> -->
 5     <!--
 6    mapper 动态代理方式使用
 7    加载 sql 映射文件的时候可以指定到 mapper 接口类
 8    但是需要满足 :
 9     1.sql 映射文件必须和 mapper 借口放在同个目录下
10     2.名称必须一致
11    -->
12     <!-- <mapper class="com.richer.mybatis.mapper.UserMapper"/> -->
13     <!--
14    与 class 方式前提条件相同, mapper 动态代理方式使用
15    -->
16     <package name="com.richer.mybatis.mapper"/>
17 </mappers>

原文地址:https://www.cnblogs.com/RicherQ/p/9106374.html

时间: 2024-08-27 13:04:23

Mybatis 框架学习的相关文章

MyBatis框架学习(一)

MyBatis介绍 MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并改名为MyBatis.2013年11月迁移到Github.iBatis一词来源于"internet"和"abatis"的组合,是一个基于Java的持久层框架.iBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAO). 当我们在DAO层使用jdb

MyBatis框架学习

MyBatis框架 1.MyBatis框架简介 目的(最大的作用):实现sql语句和java代码的分离,替代的是mvc模式中的Dao层,是持久层框架. 搭建方式: 1.配置mybatis全局配置文件: a.固定的文件头,根标签为<configuration></configuration>: b.在根标签内存在多个标签,<settings></settings>:设置日志文件打印内容的标签: <typeAliases></typeAlias

Mybatis框架学习03

写在前面 本文接https://www.cnblogs.com/wushenjiang/p/12506992.html,至此mybatis的学习已经基本完成.近一个月会进行Android的冲刺学习,所以将SSM的学习暂且滞后. 高级映射 高级映射主要分为一对一,一对多,多对多,延迟加载等.以下分别进行解释: 一对一查询(resultType实现) 需求 首先我们要提出一个需求,以便我们开展学习.需求:查询订单信息,关联查询创建订单的用户信息. po的编写 这里我们直接继承原订单类,并添加新的属性

Mybatis框架学习(四)—查询缓存与spring的整合开发

1       项目整体目录 2       查询缓存 2.1     缓存的意义 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题. 2.1    mybatis持久层缓存 mybatis提供一级缓存和二级缓存 mybatis一级缓存是一个SqlSession级别,sqlsession只能访问自己的一级缓存的数据,二级缓存是跨sqlSession,是mapper级别的缓存,对于mappe

MyBatis框架学习(二)

MyBatis中配置文件相关问题 输入参数 在传统的数据库查询操作中,在sql语句中往往需要一些参数. 1.基本数据类型 输入参数为基本数据类型时,不考虑占位符名称,将输入参数都设置给占位符. xml中配置信息: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "htt

MyBatis框架学习笔记(1)

1. Mybatis向dao层传入能够连接交互数据库并进行操作的对象 sqlSession 作用: - 向sql语句传入参数 - 执行sql语句 - 获取执行sql语句后的结果 - 事务的控制 2.  如何得到SqlSession: - 通过配置文件获取数据库连接相关信息 - 通过配置的相关信息构建SqlSessionFactory - 通过SqlsessionFactory打开 数据库会话(SqlSession) 3.  实体映射文件配置Mapper 数据库中的数据类型跟jdbc中的Type中

Mybatis框架学习总结-优化Mybatis配置文件中的配置

连接数据库的配置单独放在一个properties文件中 之前,是直接将数据库的连接配置信息卸载了Mybatis的conf.xml文件中,如下: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-

MyBatis框架学习二

增删改查操作 mapper接口本质就是原来的Dao接口,知识为了方便我们的书写,一个mapper接口对应一个mapper映射文件 将UserMapper更名为UserDao,说明本质 修改对应的mapper映射文件的namespace属性,对应上接口. 编写接口 1 package com.like.dao; 2 3 import com.like.pojo.User; 4 5 import java.util.List; 6 7 public interface UserDao{ 8 //获取

mybatis框架学习-多表查询

啰里巴嗦 mybatis中的多表查询 表之间的关系有几种: 一对多 多对一 一对一 多对多 举例: 用户和订单就是一对多 订单和用户就是多对一 一个用户可以下多个订单 多个订单属于同一个用户 人和身份证号就是一对一 一个人只能有一个身份证号 一个身份证号只能属于一个人 老师和学生之间就是多对多 一个学生可以被多个老师教过 一个老师可以交多个学生 特例: 如果拿出每一个订单,他都只能属于一个用户. 所以Mybatis就把多对一看成了一对一. mybatis中的多表查询: 示例:用户和账户 一个用户