ZB-038-01MyBatis

MyBatis是什么

  • 一个ORM框架
  • 国内基本都在用
  • 好处就是:简单/方便

为什么需要MyBatis?

之前的JDBC sql练习

注意是裸的sql 还用了PreparedStatement

我的PR

  • 过程非常痛苦
  • 不感受到痛苦就没动力学新技术

ORM

  • 对象关系映射
    • 自动完成对象到数据库的映射
  • Association
    • 自动装配对象

从零开始MyBatis

  • 官网就够了
  • 首先配置日志框架,可以极大的提高排查问题的效率
  • 然后配置数据源
  • Mapper:接口由MyBatis动态代理
    • 优点:方便
    • 缺点:SQL复杂的时候不够方便
  • Mapper:用XML编写复杂SQL
    • 优点:可以方便地使用MyBatis强大功能
    • 缺点:SQL和代码分离

数据库到底是什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
数据库实际就是一个URL

你的webApp应用
-------------
| JVM |
| | url
| |-------> Database
| | 连接串
-------------

那 MyBatis呢?

你的webApp应用
-------------
| JVM |
| | url
| |-------> Database
| MyBatis| 连接串
-------------
MyBatis它只是JVM里运行的一小段程序而已
它通过底层调用JDBC和数据库进行交互


---------
obj --> | |
|MyBatis| --> sql语句
obj <-- | |
---------

MyBatis从零开始

  • 拷贝项目在这个项目的基础上进行MyBatis配置
  • 打开官网 直接看英文
  • 点击 Getting Started
  • 看到第一段就是让你添加依赖到 pom.xml里

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>x.x.x</version>
    </dependency>
  • 然后 搜索 mybatis maven

  • 选择最近版的就行

    1
    2
    3
    4
    5
    6
    7
    添加到pom.xml里 刷新一下
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
    </dependency>
  • Building SqlSessionFactory from XML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // 文档提供了例子代码
    String resource = "org/mybatis/example/mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory =
    new SqlSessionFactoryBuilder().build(inputStream);

    // 新建一个配置文件
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    <environments default="development">
    <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
    <property name="driver" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
    </dataSource>
    </environment>
    </environments>
    <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    </mappers>
    </configuration>
  • 注意 maven的项目约定就是一切资源放在 resources 下 (图片/配置等)

  • 所以我们在 src/main/resources/db/myBatis/config.xml 内容同上
  • 运行 mvn initialize 初始化数据
  • 修改我们的配置文件src/main/resources/db/myBatis/config.xml 的内容
  • 因为我们的数据库是 h2
  • 搜h2 database driver classname 得到 org.h2.Driver
  • 修改配置为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="org.h2.Driver"/>
<!--
<property name="url" value="jdbc:h2:file:<你的项目文件夹地址>/target/test"/>
-->
<property name="username" value="root"/>
<property name="password" value="Jxi1Oxc92qSj"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 先注释掉这句 因为你还没配置 -->
<!-- <mapper resource="org/mybatis/example/BlogMapper.xml"/> -->
</mappers>
</configuration>
  • src/main/java/com.github.hcsp.sql.Sql.java
  • 修改一下
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    public class Sql {
    // 用户信息
    public static class User {
    Integer id;
    String name;
    String tel;
    String address;

    @Override
    public String toString() {
    return "User{" + "id=" + id + ", name='" + name + '\'' + ", tel='" + tel + '\'' + ", address='" + address + '\'' + '}';
    }
    }

    interface UserMapper{
    @Select("select * from user")
    List<User> getUsers();
    }

    // 注意,运行这个方法之前,请先运行mvn initialize把测试数据灌入数据库
    public static void main(String[] args) throws SQLException, IOException {
    String resource = "db/myBatis/config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory =
    new SqlSessionFactoryBuilder().build(inputStream);

    try (SqlSession session = sqlSessionFactory.openSession()) {
    UserMapper mapper = session.getMapper(UserMapper.class);
    System.out.println(mapper.getUsers());
    }
    }

    }

    // 报错了
    Exception in thread "main" org.apache.ibatis.binding.BindingException: Type interface com.github.hcsp.sql.Sql$UserMapper is not known to the MapperRegistry.
    at org.apache.ibatis.binding.MapperRegistry.getMapper(MapperRegistry.java:47)
    at org.apache.ibatis.session.Configuration.getMapper(Configuration.java:779)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.getMapper(DefaultSqlSession.java:291)
    at com.github.hcsp.sql.Sql.main(Sql.java:233)

    直接搜索这个错误 得到答案 https://stackoverflow.com/questions/4263832/type-interface-is-not-known-to-the-mapperregistry-exception-using-mybatis?r=SearchResults
    意思是你要注册一下在xml里
    <mappers>
    <mapper class="com.github.hcsp.sql.Sql$UserMapper"/>
    </mappers>

    注意 内部类要用 $

    此时成功查询出了数据

此时你该惊叹它的强大

1
2
3
4
5
6
interface UserMapper{
@Select("select * from user")
List<User> getUsers();
}

你就写了一个接口,都没去写实现,就能拿到List<User>

配置日志

在我们的 config.xml里添加官方的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<configuration>
<settings>
...
<setting name="logImpl" value="LOG4J"/>
...
</settings>
</configuration>
添加到我们的代码里

<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:file:/Users/admin/Desktop/practise-select-sql/target/test"/>
<property name="username" value="root"/>
<property name="password" value="Jxi1Oxc92qSj"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.github.hcsp.sql.Sql$UserMapper"/>
<!--<mapper resource="org/db.myBatis/example/BlogMapper.xml"/>-->
</mappers>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
</configuration>

结果 <configuration> 飙红了 为什么?
踩坑不够多

答案是 settings要放在最前面
如下
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:file:/Users/admin/Desktop/practise-select-sql/target/test"/>
<property name="username" value="root"/>
<property name="password" value="Jxi1Oxc92qSj"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.github.hcsp.sql.Sql$UserMapper"/>
<!--<mapper resource="org/db.myBatis/example/BlogMapper.xml"/>-->
</mappers>

</configuration>

运行我们的程序,结果报错了
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Priority
意思你引入了配置 但是没告诉这个类在哪 所以找不到
搜索 maven org.apache.log4j.Priority
得到 https://mvnrepository.com/artifact/log4j/log4j

复制它的坐标 到 pom.xml里
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

继续运行项目 成功 但是打印了警告信息

继续看文档,说要配置一下

1
2
3
4
5
6
7
8
9
10
新建 src/main/resources/log4j.properties 文件

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

继续运行项目,发现警告消失了

日志是需要系统学习的,因为他有不同的等级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
之所以刚刚没有任何信息打印是因为 日志等级是 ERROR

我们修改为 DEBUG

log4j.rootLogger=DEBUG, stdout

运行项目,此时能清楚的看到sql语句执行过程
DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1848125895.
DEBUG [main] - Setting autocommit to false on JDBC Connection [conn0: url=jdbc:h2:file:/Users/admin/Desktop/practise-select-sql/target/test user=ROOT]
DEBUG [main] - ==> Preparing: select * from user
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 4
[User{id=1, name='zhangsan', tel='tel1', address='beijing'}, User{id=2, name='lisi', tel='tel2', address='shanghai'}, User{id=3, name='wangwu', tel='tel3', address='shanghai'}, User{id=4, name='zhangsan', tel='tel4', address='shenzhen'}]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [conn0: url=jdbc:h2:file:/Users/admin/Desktop/practise-select-sql/target/test user=ROOT]
DEBUG [main] - Closing JDBC Connection [conn0: url=jdbc:h2:file:/Users/admin/Desktop/practise-select-sql/target/test user=ROOT]
DEBUG [main] - Returned connection 1848125895 to pool.