数据库/MyBatis学习笔记

MyBatis学习笔记(参考官方文档 3.5.4版本)

安装使用

  1. 创建Maven工程

  2. 在pom.xml中引入Maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
  1. 在resources目录下创建mybatis-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
<?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="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="这里配置数据库URL"/>
<property name="username" value="你的数据库账号"/>
<property name="password" value="你的数据库密码"/>
</dataSource>
</environment>
</environments>
<!--mappers标签关联映射,这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息-->
<mappers>
<!--这里相对路径从resources文件夹开始-->
<mapper resource="mappers/BlogMapper.xml"/>
</mappers>
</configuration>
  1. 根据官方文档给出的信息在Java目录下创建实体类、映射接口和测试类

    • Blog实体类
    1
    2
    3
    4
    5
    package entity;

    public class Blog {

    }
    • BlogMapper映射接口类
    1
    2
    3
    4
    5
    6
    7
    8
    package mapper;

    import entity.Blog;

    public interface BlogMapper {
    //创建查询方法
    Blog selectBlog(Long id);
    }
    • 创建测试类,这里使用junit单元测试类。

      • 从XML文件中构建SqlSessionFactory,获取mybatis-config.xml文件资源
      • 利用SqlSessionFactoryBuilder的build()方法创建sqlSessionFactory工厂类
      • 通过openSession()方法获取连接
      • 关联映射接口类,调用映射接口的查询方法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      @Test
      public void test01() throws IOException {
      String resource = "src/main/resources/mybatis-config.xml";
      InputStream inputStream = Resources.getResourceAsStream(resource);
      //SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      //SqlSession 的实例不是线程安全的,因此是不能被共享的
      SqlSession sqlSession = sqlSessionFactory.openSession();
      BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
      //首先得有Blog这个数据库表才能查询到数据
      Blog blog = mapper.selectBlog(1L);
      //最后需要关闭资源
      sqlSession.close();
      }

      SqlSession的实例不是线程安全的,同时映射器实例应该在调用它们的方法中被获取,使用完毕之后即可丢弃,因此,最好将映射器放在方法作用域内。就像下面的例子一样:

      1
      2
      3
      4
      try (SqlSession session = sqlSessionFactory.openSession()) {
      BlogMapper mapper = session.getMapper(BlogMapper.class);
      // 你的应用逻辑代码
      }
  1. 在resources下创建mappers文件夹用来放入mapper配置文件,创建BlogMapper接口类的映射文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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">
<!--
namespace命名就可以直接映射到在命名空间中同名的映射器类,
并将已映射的 select 语句匹配到对应名称、参数和返回类型的方法
-->
<mapper namespace="mapper.BlogMapper">
<!--id必须与映射接口中的方法名一致,resultType为返回结果类型-->
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>

对命名空间的一点补充

在之前版本的 MyBatis 中,命名空间(Namespaces)的作用并不大,是可选的。 但现在,随着命名空间越发重要,你必须指定命名空间。

命名空间的作用有两个,一个是利用更长的全限定名来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定。就算你觉得暂时用不到接口绑定,你也应该遵循这里的规定,以防哪天你改变了主意。 长远来看,只要将命名空间置于合适的 Java 包命名空间之中,你的代码会变得更加整洁,也有利于你更方便地使用 MyBatis。

对于映射类还有另一种注解的配置方法,比如,上面的 XML 示例可以被替换成如下的配置:

1
2
3
4
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}

优先使用XML配置文件的方式开发

创建完成后层级目录如下图:

XML 配置

配置文档的顶层结构如下:

属性(properties)

1
2
3
4
5
6
7
8
9
10
<!--配置数据库用户名密码-->
<!--
这些属性可以在外部进行配置,并可以进行动态替换,
既可以在典型的 Java 属性文件中配置这些属性,
也可以在 properties 元素的子元素中设置
-->
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>

设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值

1
2
3
4
5
6
7
8
9
<!--
username 和 password 将会由 properties 元素中设置的相应值来替换。 driver 和 url 属性将会由 config.properties 文件中对应的值来替换
-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>

类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

1
2
3
4
5
6
7
8
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

映射器(mappers)

1
2
3
4
5
6
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
1
2
3
4
5
6
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
1
2
3
4
5
6
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
1
2
3
4
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>

XML映射器

  • select标签
1
2
3
4
<!--select标签用于查询数据库数据,其中id为映射接口对应的方法名,必须保持一致,parameterType为接收参数类型,resultType为返回查询结果的数据类型,#{id}用以获取传入参数数值-->
<select id="selectPerson" parameterType="int" resultType="HashMap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>

官方提供的select语句的标签属性:

1
2
3
4
5
6
7
8
9
10
11
12
<select
id="selectPerson" //命名空间中唯一标识符
parameterType="int" //可选,传入参数的类全限定名或别名
parameterMap="deprecated" //已废弃
resultType="hashmap" //返回结果的类全限定名或别名
resultMap="personResultMap" //对外部 resultMap 的命名引用,resultTyperesultMap 之间只能同时使用一个
flushCache="false" //是否清空本地缓存和二级缓存,默认为false
useCache="true" //是否启用二级缓存
timeout="10" //在抛出异常之前,驱动程序等待数据库返回请求结果的秒数
fetchSize="256" //让驱动程序每次批量返回的结果行数等于这个设置值
statementType="PREPARED" //可选 STATEMENTPREPAREDCALLABLE
resultSetType="FORWARD_ONLY" //FORWARD_ONLYSCROLL_SENSITIVE, SCROLL_INSENSITIVEDEFAULT(等价于 unset) 中的一个>
  • insert、update和delete
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>

<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>

<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty="" //(仅适用于 insertupdate)指定能够唯一识别对象的属性
keyColumn="" //(仅适用于 insertupdate)设置生成键值在表中的列名
useGeneratedKeys="" //(仅适用于 insertupdate)取出由数据库内部生成的主键
timeout="20">

<update
id="updateAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">

<delete
id="deleteAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
  • 字符串替换

有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:

1
ORDER BY ${columnName}

当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。举个例子,如果你想 select 一个表任意一列的数据时,不需要这样写:

1
2
3
4
5
6
7
8
@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);

@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);

@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);

而是可以只写这样一个方法:

1
2
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);

其中 ${column} 会被直接替换,而 #{value} 会使用 ? 预处理。 这样,就能完成同样的任务:

1
2
3
User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");

Comments