Mybatis(二)(Mybatis (II))

三、优化 Mybatis 配置

我们已经在之前的学习中,学会了如何编写一个简单的 Mybatis 项目。很显然这还远远没有正真了解 Mybatis。我们从 Mybatis 核心配置文件 mybatis-config 开始优化我们的项目。

3.1 属性(properties)

在核心配置文件中 properties 是一个很重要的标签。它为 XML 提供外来配置,可以进行动态替换,其中最重要的就在于连接数据库字符串的配置。我们在 resources 文件夹下新建一个 db.properties 文件:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/kimari?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username=root
password=123456

在这之后只需要在 XML 中添加一个 properties 标签,我们就可以简化我们的 XML 文件代码了:

<properties resource="db.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>

如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:

  • 首先读取在 properties 元素体内指定的属性。
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
  • 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

3.2 类型别名(typeAliases)

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

<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>

当然你还可以直接扫描一个包来给这个包里所有的类设置类型别名:

<typeAliases>
    <package name="com.kimari.pojo"/>
</typeAliases>

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名 映射的类型
_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
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

除了用 XML 配置别名,你还可以选择用 注解来设置别名:

@Alias
@Alias("author")
public class Author {
    ...
}

3.3 设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下面是重要的几种属性:

  • cacheEnabled
    全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。默认是 true
  • lazyLoadingEnabled
    延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。默认是 false
  • mapUnderscoreToCamelCase
    是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。默认是 False
  • logImpl
    指定 MyBatis 所用日志的具体实现,未指定时将自动查找。可以选择 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
    其中 STDOUT_LOGGING 是标准日志输出,它不需要其他依赖,直接就能输出。

需要注意的是标签间的顺序都是确定的,不能随意修改。

需要注意的是标签间的顺序都是确定的,不能随意修改。

3.4 环境配置(environments)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <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>

事务管理器(transactionManager)

在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):

  • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。

数据源(dataSource)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):

  • UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
  • POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
  • JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。

3.5 映射器(mappers)

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 形式的 URL),或类名和包名等。例如:

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

注意如果使用类名和包名,接口和他的 Mapper 配置文件必须同名且必须在同一包下。

注意如果使用类名和包名,接口和他的 Mapper 配置文件必须同名且必须在同一包下。

3.6 资源过滤问题

如果出现 mapper 文件没有输出到 target 目录下,你需要在你的 pom.xml 文件中追加以下内容!

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

四、实现增删改查

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。

4.1 select

一个简单查询的 select 元素是非常简单的。比如:

<select id="getUserById" parameterType="_int" resultType="user">
    select *
    from kimari.user
    where id = #{id};
</select>

这个语句名为 getUserById,接收一个 int 类型的参数,并返回一个 User 类型的对象(由于前面已经介绍了别名,我们将省略全限命名)。先介绍几个比较重要的属性:

  • id:在命名空间中唯一的标识符,可以被用来引用这条语句。
  • parameterType:将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
  • resultType:期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
  • resultMap :对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。

如果参数类型是基础类型,则可以省略不写。

如果参数类型是基础类型,则可以省略不写。

4.2 insert, update 和 delete

数据变更语句 insert,update 和 delete 的实现非常接近:

<insert id="addUser" parameterType="user">
    insert into kimari.user(id, name, pwd)
    values (#{id}, #{name}, #{pwd});
</insert>
<update id="updateUser" parameterType="user">
    update kimari.user
    set name = #{name},
    pwd = #{pwd}
    where id = #{id};
</update>
<delete id="deleteUser">
    delete
    from kimari.user
    where id = #{id};
</delete>

下面是比较重要的属性:

  • id:在命名空间中唯一的标识符,可以被用来引用这条语句。
  • parameterType:将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。

请注意:这三个语句并没有 resultMap 和 resultType 属性。

请注意:这三个语句并没有 resultMap 和 resultType 属性。

————————

三、优化 Mybatis 配置

We have learned how to write a simple mybatis project in our previous study. Obviously, this is far from really understanding mybatis. We optimized our project from the mybatis core configuration file mybatis config.

3.1 属性(properties)

In the core configuration file, properties is a very important label. It provides external configuration for XML and can be replaced dynamically. The most important is the configuration of connection database string. We will create a new db.properties file in the Resources folder:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/kimari?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username=root
password=123456

After that, we only need to add a properties tag in the XML to simplify our XML file code:

<properties resource="db.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>

If a property is configured in more than one place, mybatis will be loaded in the following order:

  • First read the properties specified in the properties element body.
  • Then read the property file under the classpath according to the resource attribute in the properties element, or read the property file according to the path specified by the URL attribute, and overwrite the previously read property with the same name.
  • Finally, read the property passed as a method parameter and overwrite the previously read property with the same name.

Therefore, the attributes passed through the method parameters have the highest priority, followed by the configuration file specified in the resource / url attribute, and the attributes specified in the properties element have the lowest priority.

Therefore, the attributes passed through the method parameters have the highest priority, followed by the configuration file specified in the resource / url attribute, and the attributes specified in the properties element have the lowest priority.

3.2 类型别名(typeAliases)

Type alias sets an abbreviated name for a Java type. It is only used for XML configuration and is intended to reduce redundant fully qualified class name writing. For example:

<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>

Of course, you can also directly scan a package to set type aliases for all classes in the package:

<typeAliases>
    <package name="com.kimari.pojo"/>
</typeAliases>

Here are some built-in type aliases for common Java types. They are case insensitive. Note that in order to deal with the naming repetition of the original type, a special naming style is adopted.

别名 映射的类型
_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
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

In addition to configuring aliases with XML, you can also choose to set aliases with annotations:

@Alias
@Alias("author")
public class Author {
    ...
}

3.3 设置(settings)

These are extremely important tuning settings in mybatis, which change the runtime behavior of mybatis. Here are some important attributes:

  • cacheEnabled
    Globally turn on or off any cache configured in all mapper profiles. The default is true
  • lazyLoadingEnabled
    Global switch for delayed loading. When on, all associated objects are loaded late. In a specific association, the switch state of the item can be overridden by setting the fetchtype property. The default is false
  • mapUnderscoreToCamelCase
    是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。默认是 False
  • logImpl
    指定 MyBatis 所用日志的具体实现,未指定时将自动查找。可以选择 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
    其中 STDOUT_LOGGING 是标准日志输出,它不需要其他依赖,直接就能输出。

It should be noted that the order between labels is determined and cannot be modified at will.

It should be noted that the order between labels is determined and cannot be modified at will.

3.4 环境配置(environments)

Mybatis can be configured to adapt to a variety of environments. This mechanism helps to apply SQL mapping to a variety of databases. In reality, there are many reasons to do so. For example, development, test and production environments need different configurations; Or you want to use the same SQL mapping in multiple production databases with the same schema. There are many similar usage scenarios.

< strong > but remember: Although multiple environments can be configured, only one environment can be selected for each sqlsessionfactory instance

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <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>

事务管理器(transactionManager)

There are two types of transaction managers in mybatis (that is, type = “[jdbc|managed]):

  • JDBC – this configuration directly uses JDBC’s commit and rollback facilities, which rely on connections obtained from data sources to manage transaction scopes.
  • Managed – this configuration does little. It never commits or rolls back a connection, but lets the container manage the entire life cycle of the transaction (such as the context of the Jee application server). By default, it closes the connection. However, some containers do not want the connection to be closed, so you need to set the closeconnection property to false to prevent the default closing behavior.

数据源(dataSource)

The datasource element uses the standard JDBC data source interface to configure the resources of the JDBC connection object.

There are three built-in data source types (that is, type = “[unpooled | pooled | JNDI]):

  • Unpooled – the implementation of this data source opens and closes the connection each time it is requested. Although a little slow, it is a good choice for simple applications that do not require high database connection availability. Performance depends on the database used. For some databases, using connection pool is not important. This configuration is very suitable for this situation.
  • Pooled – the implementation of this data source uses the concept of “pool” to organize JDBC connection objects, avoiding the initialization and authentication time necessary to create new connection instances. This processing method is very popular and can enable concurrent web applications to respond to requests quickly.
  • JNDI – this data source implementation is to be used in containers such as EJB or application server. The container can configure the data source centrally or externally, and then place a data source reference of JNDI context.

3.5 映射器(mappers)

Now that the behavior of mybatis has been configured by the above elements, we will now define the SQL mapping statement. But first, we need to tell mybatis where to find these statements. Java does not provide a good solution for automatically finding resources, so the best way is to directly tell mybatis where to find the mapping file. You can use resource references relative to class paths, or fully qualified resource locators (including formal URLs), or class and package names. For example:

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

Note that if the class name and package name are used, the interface and its mapper configuration file must have the same name and must be under the same package.

Note that if the class name and package name are used, the interface and its mapper configuration file must have the same name and must be under the same package.

3.6 resource filtering

If the mapper file is not output to the target directory, you need to add the following contents to your pom.xml file!

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

4、 Add, delete, modify and query

The real power of mybatis lies in its statement mapping, which is its magic. Because of its extraordinary power, the XML file of the mapper is relatively simple. If you compare it with JDBC code with the same function, you will immediately find that nearly 95% of the code is saved. Mybatis is committed to reducing the use cost and enabling users to focus more on SQL code.

4.1 select

The select element of a simple query is very simple. For example:

<select id="getUserById" parameterType="_int" resultType="user">
    select *
    from kimari.user
    where id = #{id};
</select>

This statement, named getuserbyid, receives a parameter of type int and returns an object of type user (since the alias has been introduced earlier, we will omit the fully qualified naming). Let’s first introduce some important attributes:

  • ID: a unique identifier in the namespace that can be used to reference this statement.
  • Parametertype: the fully qualified name or alias of the class that will pass in the parameters of this statement. This property is optional because mybatis can infer the parameters of the specific incoming statement through the type handler. The default value is unset.
  • Resulttype: the fully qualified name or alias of the class from which the result is expected to be returned from this statement. Note that if a collection is returned, it should be set to the type contained in the collection, not the type of the collection itself. Only one can be used between resulttype and resultmap at the same time.
  • Resultmap: a named reference to an external resultmap. Result mapping is the most powerful feature of mybatis. If you understand it thoroughly, many complex mapping problems can be solved. Only one can be used between resulttype and resultmap at the same time.

If the parameter type is a base type, it can be omitted.

If the parameter type is a base type, it can be omitted.

4.2 insert, update 和 delete

The implementation of data change statements insert, update and delete is very close:

<insert id="addUser" parameterType="user">
    insert into kimari.user(id, name, pwd)
    values (#{id}, #{name}, #{pwd});
</insert>
<update id="updateUser" parameterType="user">
    update kimari.user
    set name = #{name},
    pwd = #{pwd}
    where id = #{id};
</update>
<delete id="deleteUser">
    delete
    from kimari.user
    where id = #{id};
</delete>

The following are important attributes:

  • ID: a unique identifier in the namespace that can be used to reference this statement.
  • Parametertype: the fully qualified name or alias of the class that will pass in the parameters of this statement. This property is optional because mybatis can infer the parameters of the specific incoming statement through the type handler. The default value is unset.

Note that these three statements have no resultmap and resulttype attributes.

Note that these three statements have no resultmap and resulttype attributes.