Java持久化框架-MyBatis应用

  MyBatis是支持定制化SQL、存储过程以及高级映射的优秀持久层框架。MyBatis几乎避免了所有的JDBC代码和手动设置参数,MyBatis可以对配置使用简单的XML或注解,将接口和Java的POJOs(普通Java对象)映射成数据库中的记录。

一、添加依赖

  如果使用Maven来构建项目,则需要引入如下两个依赖:


<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.3.1version>
dependency>


<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>5.1.41version>
dependency>

二、properties属性文件(config.properties)

  JDBC连接需要的driver、url以及用户信息等配置可以在Java属性文件中配置,config.properties文件配置如下:

driver=com.mysql.jdbc.Driver
## format -> jdbc:mysql://:/?property1=value1&property2=value2
url=jdbc:mysql://localhost:3306/test
username=root
password=123

  在MyBatis的XML配置文件中可以通过properties标签引入,引入后属性文件定义的值可以通过${key}方式在XML文件中引用。


...
    "config.properties">
        "username" value="root" />
        "password" value="456" />
    
...
    

  注意,properties标签除了通过resource引入外部properties文件的属性外,也可通过property标签定义属性。对于同名key,外部资源文件优先级高于property标签。

三、XML配置文件 (config.xml)

  本文使用的mybatis配置文件如下:



<configuration>

    <properties resource="config.properties">
        <property name="username" value="root" />
        <property name="password" value="456" />
    properties>

    <typeAliases>
        <typeAlias alias="User" type="com.xiaofan.test.User" />
    typeAliases>

    <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="user_mapper.xml"/>
    mappers>
configuration>

  首先,MyBatis的配置文件顶层结构如下:

- configuration
    - properties
    - settings
    - typeAliases
    - typeHandlers
    - objectFactory
    - plugins
    - environments
        - environment
            - transactionManager
            - dataSource
    - databaseIdProvider
    - mapper
  • properties

      见上节

  • settings

      settings标签是MyBatis中重要的参数调整设置标签,可通过设置其属性改变MyBatis的运行时行为。本文均采用MyBatis默认设置,详细参数设置见文档

  • typeAliases

      类别名是为Java类设置一个短的名字,它存在的意义仅在用于减少类完全限定名的冗余。如下:


...
    
        "User" type="com.xiaofan.test.User" />
    
...

  在mapper.xml文件中可将com.xiaofan.test.User全路径简写。如下:

"com.xiaofan.test.UserDAO">
...
    
    
...
  • typeHandlers

      无论是MyBatis在预处理中设置一个参数,还是从结果集中取一个值,都会用类型处理器将获取的值以合适的方式转换成Java类型,部分常用的默认处理器如下:

处理器 JDBC类型 Java类型
BooleanTypeHandler BOOLEAN java.lang.Boolean, boolean
IntegerTypeHandler NUMERIC, INTEGER java.lang.Integer, int
LongTypeHandler NUMERIC, LONG INTEGER java.lang.Long, long
FloatTypeHandler NUMERIC, DOUBLE java.lang.Double, double
StringTypeHandler CHAR, VARCHAR java.lang.String
DateTypeHandler TIMESTAMP java.util.Date

  除了以上默认类型处理器件外,也可以通过实现org.apache.ibatis.type.TypeHandler或继承org.apache.ibatis.type.BaseTypeHandler来重写或创建自己的类型处理器。配置文件如下


...
    
        "your handler path" />
    
...
  • objectFactory

      MyBatis每次创建结构对象的新实例时,都会使用一个对象工厂(objectFactory)实例来完成,默认的对象工厂仅仅是实例化目标类,如果参数映射不存在,则通过默认构造方法完成实例化,如果存在参数映射,则通过参数构造方法完成实例化。也可以通过创建自己的对象工厂完成实例化。

  • plugins

    MyBatis允许在已映射语句执行过程中的某一点进行拦截,默认情况下,MyBatis允许使用插件来拦截的方法包括:Executor、ParameterHandler、ResultSetHandler、StatementHandler。

  • environments

      MyBatis可以配置成适应多种环境,这种机制有助于将SQL映射用于多种数据库,每个环境需要创建一个独立的SqlSessionFactory实例,每个数据库对应一个。一份MyBatis环境配置示例如下:

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

  MyBatis中有两种类型的事务管理器(type=”[JDBC|MANAGED]”)。
  JDBC:使用JDBC的提交和回滚设置,它依赖于数据源得到的连接来管理事务作用域;
  MANAGED:它不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。如果使用Spring+MyBatis,则没必要配置事务管理器,因为Spring会使用自带的管理器覆盖前面的设置。

  MyBatis有三种内建的数据源类型(type=”[UNPOOLED|POOLED|JNDI]”)。
  UNPOOLED:顾名思义,该数据源类型将不使用连接池,每次被请求时打开和关闭连接。缺点时慢,它对没有性能要求的简单应用程序中是个很好的选择。它的必要属性:
    driver:JDBC驱动的Java类完全限定名
    url:数据库JDBC 的URL地址
    username:登录数据库的用户名
    password:登录数据库的密码
    defaultTransactionIsolationLevel:默认的连接事务隔离级别

  POOLED:该类型利用数据库连接池,避免了创建新数据库连接时需要的初始化和认证时间。这是兵法Web应用快速响应请求的流行处理方式。
     poolMaximumActiveConnections:任意时间可存在的连接数,默认:10
     poolMaximumIdleConnections:任意时间可存在的空闲连接数
     poolMaximumCheckoutTime:被强制返回前,池中连接被checkout时间,默认:20秒
     poolPingQuery:发送侦测查询到数据库。默认:NO PING QUERY SET
     poolPingEnabled:是否启用侦测查询。默认:false
     poolPingConnectionsNotUsedFor:poolPingQuery的使用频度。默认:0
  JNDI:该数类型的实现是为了能在如EJB或应用服务器这类容器中使用,容器可集中或在外部配置数据源,然后放置在一个JNDI上下文中。

  • databaseIdProvider

      MyBatis可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的databaseId属性。

  • mappers

      mappers标签是让MyBatis查找映射文件,从而能够获取到SQL映射语句。其中映射文件的路径可以是资源文件路径的相对路径,也可以是绝对路径。使用范例如下


...
    
        "user_mapper.xml"/> 
    
...

注意,properties、setting、typeAliases等configuration子标签必须按以上顺序设置,顺序设置错误会导致如下错误:

org.xml.sax.SAXParseException; ... 元素类型为 "configuration" 的内容必须匹配 "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,plugins?,environments?,databaseIdProvider?,mappers?)"

四、XML映射文件 (user_mapper.xml)

  MyBatis的SQL映射功能强大,它能极大的简化SQL构建。SQL映射文件的顶级元素如下:

cache : 给定命名空间的缓存配置
cache-ref : 其他命名空间缓存配置的引用
resultMap : 描述如何从数据库结果集中加载对象
sql : 可以被其他语句引用的可重用语句块
insert : 插入语句
update : 更新语句
delete : 删除语句
select : 查询语句

  本文demo使用的一个简单的MyBatis XML映射文件如下:



<mapper namespace="com.xiaofan.test.UserDAO">

    <resultMap id="UserResultMap" type="User">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
    resultMap>

    <sql id="tmpSql" >
        select * from ${realdb}
    sql>

    <insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        insert into user(name,age) values(#{name},#{age})
    insert>

    <insert id="batchInsert" useGeneratedKeys="true" keyProperty="id">
        insert into user(name, age) values
        <foreach item="item" collection="list" separator=",">
            (#{item.name}, #{item.age})
        foreach>
    insert>

    <update id="update" parameterType="User">
        update user set name=#{name},age=#{age} where name=#{name}
    update>

    <delete id="delete" parameterType="String">
        delete from user where name=#{name}
    delete>

    <select id="findByName" resultMap="UserResultMap">
        <include refid="tmpSql">
            <property name="realdb" value="user" />
        include>
        where name=#{name}
    select>

    <select id="selectAll" resultType="User">
        select * from user
    select>

mapper>

insert/update/delete/select

  以上配置文件中的select、insert、update、delete元素没有使用太多属性,其实,MyBatis为CRUD元素提供了丰富的属性可选。部分常用属性配置如下

属性 描述 默认值
id 在命名空间中唯一的标识符,可用该标识来引用这条语句
parameterType [可选] 当前语句参数类的完全限定名或别名,MyBatis可通过TypeHandler推断 unset
resultType 返回的期望类型类的完全限定名或别名。注意:如果是集合,则resultType是集合包含的类型,如List中的E
resultMap 引用外部定义的resultMap,如果是集合情况如resultMap。resultType和resultMap不可同时使用
timeout 驱动程序等待数据库返回的时间(秒),超过时间抛出异常 unset
useGeneratedKeys (insert/update)允许MyBatis使用JDBC的getGeneratedKeys方法取出数据库内部生成的主键 false
keyProperty (insert/update)MyBatis通过getGeneratedKeys的返回值或insert语句的selectKey子元素设置它的键值 unset

sql

  sql标签可以用来定义可重用的SQL代码片段,可以包含在其他语句中。它可以被静态地参数化(可不指定),不同的实例拥有不同的属性值。一份sql可重用片段如下:

...
     "tmpSql" >
        select * from ${realdb}
    
...
    
...

resultmap

  resultmap元素可以避免像JDBC那样需要从结果集中去处数据的代码。如下情况MyBatis会使用Javabean User来作为领域模型,MyBatis会默认在幕后自动创建一个ResutlMap,基于属性名来映射到JavaBean的属性上,如果列名没有精确匹配,也可以通过select as来指定别名来匹配, 如果User有nameAlias属性,则该属性会被赋name的返回值。

...
    
...

resultmap属性说明

resultmap
    - constructor : 构造方法注入,可不用暴露公共方法
    - id : 标记结果作为ID
    - result : 注入到字段或JavaBean属性的普通结果
    - association : 关联嵌套结果
    - collection : 集合嵌套结果
    - discriminator : 鉴别器,作用类似Java的Switch

 
  构造方法注入可在初始化时为类设置属性的值,不用暴露公共的方法,resultmap的constructor属性用法如下:

User类:
public class User {
...
    User(Long id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
...
}

xml映射文件:
"com.xiaofan.test.UserDAO">
...
    "UserResultMap" type="User">
        
            "id" javaType="long" />
            "name" javaType="String" />
            "age" javaType="int" />
        
    
    
...

五、动态SQL

  MyBatis的强大特性之一是它的动态SQL,它允许你根据不同条件拼接不同的SQL语句。MyBatis提供的动态SQL元素如下

- if
- choose(when, otherwise)
- trim(where, set)
- foreach

if

if基本使用方法如下, 该语句可动态选择是否加入age筛选条件。

...
    
...

choose(when, otherwise)

  当只想从条件中选择其中一个时,可以使用choose元素,类似Java中的Switch,多个条件匹配时返回第一个匹配的条件。使用范如下:

...
    
...

trim(where, set)

  trim或where、set元素是用来解决条件元素匹配带来的多余连接符。其中where使用范例如下,他会自动去掉多余的and或or链接符号

...
    
...

等同于:

...
    
...

  set使用范例如下:

...
    "update" parameterType="User">
        update user
        
            <if test="name != null">
                name = #{name},
            if>
            <if test="age != null">
                age =#{age},
            if>
        
        where id = #{id}
    
...

等同于:

...
    "update" parameterType="User">
        update user
        "set" suffixOverrides=",">
            <if test="name != null">
                name = #{name},
            if>
            <if test="age != null">
                age =#{age},
            if>
        
        where id = #{id}
    
...

foreach

  foreach元素允许指定一个集合,并对该集合进行遍历。当使用可迭代对象或者数组时,index时但前迭代的次数,item时本次迭代的元素;当使用Map.Entry时,index是键,item是值。

...
    "batchInsert" useGeneratedKeys="true" keyProperty="id">
        insert into user(name, age) values
        "item" index="idx" collection="list" separator="," >
            (#{item.name}, #{item.age})
        
    
...

六、JAVA API使用

  MyBatis提供的主要Java接口是SqlSession,可以通过这个接口执行命令、获取映射器和管理事务。SqlSession是由SqlSessionFactory实例创建,SqlSessionFactory实例包含创建SqlSession实例的所有方法,SqlSessionFactory是由SqlSessionFactoryBuilder创建,SqlSessionFactoryBuilder可以通过XML配置来创建SqlSessionFactory。一个完整的调用示例如下:

public class Test {

    public static void main(String [] args) {

        try {

            String resource = "config.xml";
            Reader reader = Resources.getResourceAsReader(resource);
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(reader);
            SqlSession session = factory.openSession();
            UserDAO userDAO = session.getMapper(UserDAO.class);
            userDAO.batchInsert(Lists.newArrayList(new User(null, "test1", 11), new User(null, "test2", 12)));
            session.commit();
            User user = userDAO.findByName(new User(null, "test1", null));
            System.out.println(JSON.toJSONString(user));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

配置文件读取

  默认情况下,MyBatis加载资源文件的默认路径是src/main, 如果需要指定其他路径,需在项目POM文件中指定资源文件路径。以上config.xml文件添加在resources资源文件夹下,因此需要将resources文件夹添加微资源加载路径,以保证config.xml文件能够被正确加载。

...
    
        xiaofantest
        
            
                src/main/resources
                true
                
                    *.*
                
            
        
    
...

SqlSessionFactory

  SqlSessionFactory有六个方法可以创建SqlSession,其中使用较多的有两个,如下。默认openSession()方法没有参数,创建的SqlSession会开启一个事务,该事务需要用户自己提交。如果将创建参数autoCommit设置为‘true’,SqlSession则会开启自动提交功能。

SqlSession openSession()
SqlSession openSession(boolean autoCommit)

SqlSession

  SqlSession有超过20个方法,这些方法呗用来执行定义在SQL XML映射文件中的select、insert、update、delete语句,每一条语句都适用语句的ID属性和参数对象,参数可以是原声类型、JavaBean、POJO或Map。常用的方法如下:

// 带参数的方法
 T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)
// 不带参数的方法
 T selectOne(String statement)
<E> List<E> selectList(String statement)
<K,V> Map<K,V> selectMap(String statement, String mapKey)
int insert(String statement)
int update(String statement)
int delete(String statement)
// 查询方法的高级版本
<E> List<E> selectList (String statement, Object parameter, RowBounds rowBounds)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)
void select (String statement, Object parameter, ResultHandler handler)
void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler handler)

  对于如下一个sql 映射语句配置,有两种执行该sql的方式。一种是映射语句mapper的namespace+statementId; 另一种是指定mapper接口。

...
    
...

  第一种方式示例:一个带参数的简单查询语句如下:

...
User user = session.selectOne("com.xiaofan.test.UserDAO.findByName", new User(null, "Jerry", null));
...

  第二种方式示例:指定mapper(映射器)对应的接口,每个映射器方法签名应该没有关联的字符串参数ID,但方法名必须与sql映射语句ID一致。

mapper接口定义:
public interface UserDAO {
...
    User findByName(User user);
...
}

Java方法调用:
...
    UserDAO userDAO = session.getMapper(UserDAO.class);
    User user = userDAO.findByName(new User(null, "test1", null));
...

映射器配置

  MyBatis sql映射器配置方式有两种,一种是写sql映射xml文件,并在MyBatis配置文件中添加mapper;另一种是在mapper接口中通过注解的方式配置sql映射语句。

  通过xml配置sql映射示例如下:

mapper接口定义:
public interface UserDAO {
...
    User findByName(User user);
...
}

sql映射文件:
"com.xiaofan.test.UserDAO">
...
    
...


MyBatis配置文件:

...
    
        "user_mapper.xml"/>
    
... 

  第二种方式,通过注解方式定义mapper接口示例如下, 更多注解说明见文档:

Mapper接口类:
public interface UserDAO {
...
    @Select("select * from user where name = #{name}")
    User findByName(User user);
...
}

MyBatis配置文件:

...
    
        "com.xiaofan.test.UserDAO" />
    
...    

你可能感兴趣的:(数据库,框架设计,java,mybatis,框架,数据库,注解)