MyBatis入门

MyBatis主要组成部分

clipboard.png
1. SqlSessionFactoryBuilder(构造器)

根据配置信息或代码生成SqlSessionFactory接口

2. SqlSessionFactory(工厂接口)

依靠工厂来生成SQLSesson(会话)

3. SqlSession(sql处理器)

既可以发送SQL去执行并返回结果,也可以获取Mapper的接口

4. SQL Mqapper(映射规则及SQL定义)

MyBatis的新设计组件,由Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则。负责发送SQL去执行。并返回结果。

SqlSessionFactory

MyBatis的应用都是以SqlSessionFactory的实例为中心。SqlSessionFactory的实例是由SqlSessionFactoryBuilder生成的。

注:SqlSessionFactory是一个工厂接口,不是实现类

SqlSessionFactory的任务是创建SQLSession。SQLSession类似于JDBC的Connection对象。

可用XML配置和代码方式创建SQLSessionFactory,推荐使用XML配置方法

SQLSession

SqlSession是一个接口类,相当于前台,主要和程序员交接,调用Executor接口执行相应操作。SqlSession在中间负责接收功能参数,之后返回结果(是一个黑箱操作)

SQLSession类似于JDBC中的Connection对象,需要及时关闭

SQLSession的执行包括两种方法:1.获取映射器,让映射器通过命名空间和方法名称找到对应的SQL,发送到数据库并执行。2.直接通过命名信息去执行SQL并返回结果。在SQLSession层可以通过update,insert,select,delete等方法,带上SQL的id来操作在XML中配置的SQL,进而完成工作。也支持事物,通过commit和rollback方法提交或者回滚事物。


clipboa1rd.png

映射器 (XML Mapper和Java接口)

映射器是由Java接口和XML文件(或注解)组成,作用是:

  • 定义参数类型。
  • 描述缓存。
  • 描述SQL语句。
  • 定义查询结果和POJO的映射关系。

映射器有两种实现方式,1. xml文件描述。2. java代码实现,添加注解方式。

建议使用xml方式

MyBatis生命周期

SQLSessionFactoryBuilder

利用xml配置文件或java编码构建SQLSessionFactory,可构建多个SQLSessionFactory。它是一个构建器,一旦构建出SQLSessionFactory,它的作用就完成了。只存在于方法的局部,作用就是生产SQLSessionFactory。

SQLSessionFactory

SQLSessionFactory的作用是创建SQLSession,每次访问数据库都需要它来创建SQLSession,所以SQLSessionFactory存在于MyBatis的整个生命周期。

通常一个数据库对应一个SQLSessionFactory,避免消耗过多的数据库连接资源。

SQLSession

SQLSession是一个会话,它的生命周期是在请求数据库处理事务的过程当中,相当于JDBC的Connection对象,属于==线程不安全对象==,在涉及多线程时需格外注意,操作数据库需要注意其隔离级别,数据库锁等高级特性。创建并使用完SQLSession后必须及时

关闭,减少资源占用。

Mapper

Mapper是一个接口,没有任何实现类,作用是发送SQL,再返回需要的结果或执行SQL修改数据库的数据。 它是在一个SQLSession事物的方法中使用的,然后废弃。

Mybatis设置

<?xml version = "1.0" encoding = "UTF-8"?>
<configuration><!--配置-->
    <properties/><!--属性-->
    <settings/><!--设置-->
    <typeAliases/><!--类型命名-->
    <typeHandlers/><!--类型处理器-->
    <objectFactory/><!--对象工厂-->
    <plugins/><!--插件-->
    <environments><!--配置环境-->
        <environment><!--环境变量-->
            <transactionManager/><!--事物管理器-->
            <dataSource/><!--数据源-->
        </environment>
    </environments>
    <databaseIdProvider/><!--数据库厂商标识-->
    <mappers/><!--映射器-->
</configeration>    
    

properties元素

properties是个配置属性的元素,配置文件的上下文中使用。

三种配置方式

  1. property子元素
  2. properties配置文件
  3. 程序参数配置

property子元素

property子元素配置代码如下:

<properties>
    <property name = "dirver" value = "com.mysql.jdbc.Dirver"/>
    <property name = "url" value = "jdbc:mysql://localhost:3306/mybatis"/>
    <property name = "username" value = "root"/>
    <property name = "password" value = "123"/>
</properties>

这样我们就可以在上下文中使用配置好的properties属性值。

<dataSourse type = "POOLED">
    <property name = "dirver" value = "${dirver}"/>
    <property name = "url" value = "${url}"/>
    <property name = "username" value = "${username}"/>
    <property name = "password" value = "${password}"/>
</dataSourse>

properties配置文件

使用properties配置文件可让多个配置文件重复使用

<!--jdbc.properties-->
dirver = com.mysql.jdbc.Dirver
url = jdbc:mysql://localhost:3306/mybatis
username = root
password = 123

引用变量代码如下:

<properties resource = "jdbc.properties"/>

程序参数传递

在实际对于用户名密码需要进行加密处理,则需要让jdbc.properties中的username和password两个属性使用加密字符串,需要在生产SQLSessionFactory之前转化为明文,使用系统提供的decode(str)方法解密。使用代码方式创建SQLSessionFactory:

InputStream cfgStream = null;
reader cdgReader = null;
InputStream proStream = null;
Reader proReader = null;
Properties properties = null;
try{
    //读入配置文件流
    cfgStream = Resources.getResourceAsStream("MyBatis-config.xml");
    cfgReader = new InputStreamReader(cfgStream);
    //读入属性文件
    proStream = Resources.getResourceAsStream("jdbc.properties");
    proReader = new InputStreamReader(proStream);
    properties = new Properties();
    properties.load(proReader);
    //解密为明文
    properties.setProperty("username",decode(properties.getProperty("username")));
    properties.setProperty("password",decode(properties.getProperty("password")));
}catch (IOException ex){
    Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SERVRE,null,ex);
}
sysnchronized(CLASS_LOCK){
    if(sqlSessionFactory == null){
        //使用属性来创建SQLSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().builder(cfgReader,properties);
    }
}

三种配置优先级

通过方法传递 > 读取properties文件 > property直接指定

三种方法不要混合使用,容易造成管理混乱。
优先使用读取properties文件方式。

设置

设置(setting)是MyBatis最复杂的一块配置,也是最重要的配置块之一。
它会改变MyBatis的运行行为,但是即使不配置setting,MyBatis也能正常使用。
完整的setting配置如下:

<settings>
    <setting name = "cacheEnabled" value = "true"/>
    <setting name = "lazyLoadingEnabled" value = "true"/>
    <setting name = "multipleResultSetsEnabled" value = "true"/>
    <setting name = "useColumnLabel" value = "true"/>
    <setting name = "useGenerateKeys" value = "false"/>
    <setting name = "autoMappingBehavior" value = "PARTIAL"/>
    <setting name = "defaultExcutorType" value = "SIMPLE"/>
    <setting name = "defaultStatementTimeout" value = "25"/>
    <setting name = "safeRowBoundsEnabled" value = "false"/>
    <setting name = "mapUnderscoreToCamelCase" value = "false"/>
    <setting name = "localCacheScope" value = "SESSION"/>
    <setting name = "jdbcTypeForNull" value = "OTHER"/>
    <setting name = "lazyLoadTriggerMethods" value = "equals,clone,hashCode,toString"/>
</settings>

大多时候不必配置他们,或只需配置少数几项。

别名

别名(typeAliases)是一个指代名称,当遇到类全限定名过长时,我们使用typeAliases去代替它。这个名称在MyBatis上下文中使用。别名在MyBatis中分为系统定义别名和自定义别名两类。

别名不区分大小写。

一个typeAliases的实例是在解析配置文件时生成的,然后长期保存在configuration对象中,当我们使用时就不必再次运行生成实例了。

系统自定义别名

MyBatis系统定义了一些经常使用的类型的别名,例如:数值,字符串,日期集合等,可以在MyBatis中直接调用,不要重复定义把他们覆盖。

自定义别名

MyBatis允许自定义别名,代码例如:

<!--自定义别名-->
<typeAliases>
    <typeAlias alias = "role" type = "com.learn.chapter2.po.Role"/>
</typeAliases>

当自定义别名过多时,可以定义自动扫描包的范围,并在需要定义的类的上方加注解即可批量定义别名。

<!--扫描包,批量定义别名-->
<typeAliases>
    <package name = "com.learn.chapter2.po"/>
    <package name = "com.learn.chapter3.po"/>
</typeAliases>
/*
*别名注解
*/
@Alias("role")
public class Role{
    //some code
}

不加注解也能加载别名,默认将类名第一个字母变为小写,故一定要避免重名。

typeHandler类型处理器

MyBatis在预处理语句(prepareStatment)中设置一个参数,或从结果集(ResultSet)中取出一个值时,都会用注册了的typeHandler进行处理。

由于数据库的厂商不同,不同的厂商设置的参数可能不同,数据库也可以自定义数据类型,typeHandler允许根据项目的需要自定义设置java传递到数据库的参数中,或者从数据库读出数据,也需要进行特殊处理,这些都是在自定义typeHandler中处理,尤其是枚举类型常常需要使用typeHandler来进行转换。

typeHandler分为系统定义和自定义两种,一般系统定义可满足绝大部分功能。自定义typeHandler务必小心谨慎。

typeHandler常用配置为javaType和jdbcType,作用是将JavaType转化为jdbcType,或者将数据库取出结果从jdbcType转化为JavaType。

.......

ObjectFactory

mybatis在构建一个结果返回的时候,需要用到ObjectFactory(对象工厂)去构建POJO,在MyBatis中也可以定制自己的对象工厂。一般使用默认的ObjectFactory即可。

自定义ObjectFactory需要进行配置

<objectFactory type="com.learn.chapter3.objectFactory.MyObjectFactory">
    <property name="name" value="MyObjectFactory" />
</objectFactory>

自定义ObjectFactory需要刷新ObjectFactory接口,而系统自带的DefaultObjectfactory已经实现了ObjectFactory接口,故只需让myObjectFactory基础DefaultObjectFactory即可。实例如下:


//MyObjectFactory
packgae com.learn.chapter3.objectFactory;
improt java util.List;
import java.util.Properties;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.log4j.Logger;

public class MyObjectFactory extends DefaultObjectFactory{
    
    private static final long serialVerSionUID = -381482721604028629L;
    Logger log = Logger.getLogger(MyobjectFactory.class);
    
    @Override
    public void setProperties(Properties prprty){
        log.info("定制属性:"+prprty);
        super.setProperties(prprts);
    }
    
    @Override
    public <T> T create(Class<T> type){
        log.info("使用定制对象工厂的create的方法构建单个对象");
        return super.create(type);
    }
    
    @Override
    public <T> T create(Class<T> type, List<Class<?>> list, List<Objetc> list1){
        log.info("使用定制对象工厂的create方法构建列表对象");
        return super.create(type,list,list1);
    }
    
    @Override
    public <T> boolean isCollection(Class<T> type){
        return super.isCollection(type);
    }
    
}

插件

比较复杂,会出现一些覆盖MyBatis内部核心的行为。

environment配置环境

注册数据源

配置环境可以注册多个数据源(dataSource),每个数据源需要进行数据库源配置及数据库事物(transactionManager)配置。

连接池数据配置示例:

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC">
            <property name="autoCommit" value="false"/>
        </transactionManager>
        <dataSource type="POOLED">
            <property name="dirver" value="com.mysql.jdbc.Dirver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/oa"/>
            <property name="username" value="root"/>
            <property name="password" value="123"/>
        </dataSource>
    </environment>
</environments>

上述代码中environments中default属性,标明在缺省情况下启用哪个数据源。

  • environment元素是配置一个数据源的,属性id是设置这个数据源的标识,以方便mybatis在上下文中使用它。
  • transactionManager配置数据源的数据库事物,其中type属性有三种配置方式。
  1. JDBC,采用JDBC方式管理事物,在独立编码中常常使用。
  2. MANAGED,采用容器的方式管理事物,在JNDI数据源中使用。
  3. 自定义,由使用者自定义数据库事物管理办法,适用于特殊应用。
  • property元素可以配置数据源各类属性,这里的autoCommit=false,则是要求数据源不自动提交。
  • dataSource标签配置的是数据源的连接信息,type属性提供数据库的连接方式的配置,在mybatis中有几种连接方式:
  1. UNPOOLED,非连接池数据库。
  2. POOLED,连接池数据库
  3. JNDI,JNDI数据源。
  4. 自定义数据源。
    其中property元素是定义数据库连接的各类参数。

数据库事物

数据库事务Mybatis交由SqlSession控制,可以通过SqlSession提交(commit)或者回滚(rollback)。插入一个角色对象,如果成功就提交,否则就回滚。

try{
    sqlSession = SqlSessionFactoryUtil.openSqlSession();
    RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
    int count = roleMapper.insertRole(role);
    sqlSession.commit();
    return count;
}catch(Exception ex){
    sqlSession.rollback();
}finally{
    sqlSession.close();
}

大部分时候都是用Spring框架控制数据库事物

dataSourceIdProvider数据库厂商标识

可选择使用系统默认规则和不使用系统默认规则。

引入映射器的方法

映射器是mybatis最复杂,最核心的组件。

  • 首先定义映射器接口
package com.learn.chapter3.mapper;
import java.util.List;
import com.learn.chapter3.po.Role;
public interface RoleMapper {
    public Role getRole(Long id);
}
  • 其次给出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="com.learn.chapter3.mapper.RoleMapper">
<select id="getRole" paramenterType="long" resultType="com.learn.chapter3.po.Role">
    select id,role_name as roleName, note from t_role where id=#{id}
</select>
</mapper>

引入映射器的常用方法:

  1. 用文件路径引入映射器
<mappers>
    <mapper resource="com/learn/chapter3/mapper/roleMapper.xml"/>
</mappers>

  1. 用包名映入映射器
<mappers>
    <package name="com.learn.chapter3.mapper"/>
</mappers>

  1. 用类注册引入映射器
<mappers>
    <mapper class="com.learn.chapter3.mapper.UserMapper"/>
    <mapper class="com.learn.chapter3.mapper.RoleMapper"/>
</mappers>

  1. 用userMapper.xml引入映射器
<mappers>
    <mapper url="file:///var/mappers/com/learn/chapter3/mapper/roleMapper/xml"/>
    <mapper url="file:///var/mappers/com/learn/chapter3/mapper/RoleMapper.xml"/>
</mappers>

映射器

MyBatis是针对映射器构造的SQL构建的轻量级框架,并且通过配置生成对应的JavaBean返回给调用者,这些配置主要便是映射器。

映射器的主要元素

  • select ,查询语句,最常用最复杂的元素。可以自定义参数,返回结果集等
  • insert, 插入语句。执行后返回一个整数,代表插入的条数。
  • update,更新语句。执行后返回一个整数,代表更新的条数。
  • delete,删除语句。执行后返回一个整数,代表删除的条数。
  • parameterMap,定义参数映射关系。即将被删除的元素,不建议使用。
  • sql, 允许定义一部分的SQL,然后可在各个地方引用它。
  • resultMap, 用来描述从数据库中结果集中来加载对象,最复杂,最强大的元素。
  • cache,给命名空间缓存配置。
  • cache-ref,其他命名空间缓存配置引用。

select

简单select数据类型的例子

<select id="countFirstName" parameterType="String" resultType="int">
    select count(*) as total from t_user where name like concat(#{firstName},'%')
</select>

在Dao接口中定义方法

public int countFirstName(String firstName);
  • id 标出了这条sql
  • paramenterType 定义参数类型
  • resultType定义了返回值类型

自动映射

setting元素中有autoMappingBehavior参数,当它不设置为NONE时,MyBatis会设置自动映射功能。只要返回的Sql的列名和javaBean的属性一致,mybatis会帮我们回填这些字段,无需任何配置。

注:数据库规范单词间用下划线分隔,java中使用驼峰式命名,可以使用列的别名使mybatis自动映射,也可以直接配置文件中开启驼峰式命名方式。

传递多个参数

使用map传递多个参数

使用Map接口作为参数实现多参数传递

<select id="findRoleByMap" parameterType="map" resultMap="roleMap">
    select id, role_name, note 
    from t_role
    where role_name like concat('%',#{roleName},'%')
    and note like concat('%',#{note},'%')
</select>

RoleDao接口:

public List<Role> findRoleByMap(Map<String,String> params);

参数传递代码如下:

Map<String,String> paramsMap = new HashMap<String,String>();
    paramsMap.put("roleName", "me");
    paramsMap.Put("note","te");
role 
clipbo32ard.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,465评论 0 4
  • MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架。MyBatis 摒除了大部分的JDBC代码、...
    七寸知架构阅读 6,698评论 6 56
  • 什么是mybatis MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis...
    seadragonnj阅读 2,325评论 0 7
  • 第一次看见这句话是在蔡崇达的《皮囊》中。当他开始回头观望自己过往的生命历程时,看到一个与当时自己不一样的视角。而这...
    洛瑶的乐园阅读 441评论 0 2
  • 第一题 在不同领域我们总能看到像天才一样的人,感觉他比别人都有天赋。但是经过作者30多年对这些“天才”研究发现,这...
    小莎妹儿阅读 144评论 0 0