mybatis

mybatis的基本构成

mybatis:持久层、简化工作量、灵活
Spring:粘合剂 整合框架、AOP、IOC、DI
SpringMVC:表现层 方便前后端数据的传输

mybatis是对jdbc 的封装
将SQL语句映射到文件(XML)上
自动将输入参数映射到SQL语句的动态参数上
自动将SQL语句执行的结果映射成java 对象
SqlSessionFactoryBuilder(构造器):它会根据配置信息或者代码来生成SqlSessionFactory(工厂接口)
SqlSessionFactory:依靠工厂来生成SqlSession(会话)
SqlSession:是一个既可以发送SQL去执行并返回结果,也可以获取Mapper的接口。
SQL Mapper:它是MyBatis新设计的组件,它是由一个Java接口和XML文件(或注解)构成的,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。

SqlSessionFactoryBuilder--------->SqlSessionFactory
										|
										|
		-----SQL Mapper<----------SqlSession
		|							|
		|							|
			<---------------------
构建SqlSessionFactory
每个MyBatis的应用都是以SqlSessionFactory 的实例为中心的。
SqlSessionFactory 的实例可以通过SqlSessionFactoryBuilder获得。
SqlSessionFactory 是一个工厂接口而不是现实类,它的任务是创建 SqlSession。
SqlSession类似于一个的JDBC 的 Connection。
Mybatis 提供了两种模式去创建SqlSessionFactory:
	一种是XML`配置的方式
	另一种是代码的方式
使用XML方式构建
包含获取数据库连接的数据源(DataSource)、决定事务范围和控制方式的事务管理器(TransactionManager)和映射器(SQL Mapper)。
MyBatis-config.xml
<?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>
    <!-- 定义别名 -->
	<typeAliases>
        <typeAlias alias="girl" type="com.dumbo.pojo.Girl"/>
    </typeAliases>
    <!-- 定义数据库信息,默认使用development 数据库构建环境 -->
    <environments default="dev">
        <environment id="dev">
            <!-- 采用JDBC事务管理 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据库链接信息 -->
            <dataSource type="UNPOOLED">
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="username" value="root"/>
                <property name="password" value="123"/>
            </dataSource>
        </environment>
    </environments>
	<!-- 定义映射器 -->
    <mappers>
        <mapper resource="com/dumbo/mapper/GirlMapper.xml"></mapper>
    </mappers>
</configuration>
它的作用是提供SQL 和SQL 对POJO 的映射规则定义,它包含了映射器里面的信息。MyBatis 将解析这个XML,来为我们生成映射器。
生成SqlSessionFactory
package com.dumbo.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtil {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        String resource = "MyBatis-config.xml";
        InputStream in = null;
        try {
            in = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static SqlSession getSession(){
        return sqlSessionFactory.openSession();
    }
}
创建了一个XML文件输入流,用SqlSessionFactoryBuilder 读取XML的信息来创建SqlSessionFactory 的对象。
MyBatis的解析程序会将MyBatis-config.xml文件配置的信息解析到Configuration 类对象里面,然后利用SqlSessionFactoryBuilder 读取这个对象后创建SqlSessionFactory。
创建SqlSession
SqlSession是一个接口类
MyBatis中SqlSession接口的实现类有两个:
    DefaultSqlSession
    SqlSessionManager
    
构建了SqlSessionFactory,然后生成MyBatis的门面接口SqlSession。SqlSession 接口类似于一个JDBC中的Connection 接口对象,必须保证每次用完之后正常关闭它,所以正确的做法是把关闭SqlSession接口的代码写在finally语句中保证每次都会关闭SqlSession,让连接资源归还给数据库
标准的SqlSession使用方法
SqlSession sqlsession = null;
try {
	//打开SqlSession会话
	sqlSession = sqlSessionFactory.openSession();
	sqlSession.commit();
} catch(Exception ex) {
	System.err.println(ex.getMessage());
	sqlSession.rollback();
} finnally {
    //在finally语句中确保资源被顺利关闭
	if(sqlSession != null){
		sqlSession.close();
	}
}
SqlSession的用途主要有两种:
    获取映射器,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行后返回结果。
    直接通过命名信息去执行SQL返回结果,这是iBatis版本留下来的方式。在SqlSession层可以通过updata、insert、select、delete等方法,带上SQL的id来操作在XML中配置好的SQL,通过commit、rollback方法提交或者回滚事务。
映射器
映射器是由Java接口和XML文件(或注解)共同组成的
作用:
    定义参数类型
    描述缓存
    描述SQL语句
    定义查询结果和POJO映射关系
映射器实现方法
    一种是通过XML文件方式实现,mybatis-config.xml文件中已经描述了一个XML文件,它是用来生成Mapper的
    另一种是通过代码实现,在Configuration里面注册Mapper接口。
XML文件配置方式实现Mapper
第一步:定义接口

package com.dumbo.mapper;

import com.dumbo.pojo.Girl;

public interface GirlMapper {
    int insert(Girl girl);
}
第二步:映射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.dumbo.mapper.GirlMapper">
    <insert id="insert">
        insert into girl (name,flower,birthday) values (#{name},#{flower},#{birthday})
    </insert>
</mapper>
描述XML文件做了什么
package com.dumbo.mapper;

import com.dumbo.pojo.Role;

public interface RoleMapper{
	public Role getRole(Long id);
}


<?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.dumbo.mapper.RoleMapper">
    <select id="getRole" parameterType="long" resultType="role">
		select id,role_name as rolename,note from role where id = #{id}
	</select>
</mapper>
这个文件是我们配置的mybatis-config.xml中配置的,所以MyBatis会读取这个配置文件,生成映射器。
定义了一个命名空间为com.dumbo.mapper.RoleMapper的SQL Mapper,这个命名空间和我们定义的接口全限定名是一致的。

用一个select 元素定义了一个插入SQL,id为getRole,和我们接口方法是一致的,而 parameterType则表示我们传递给这条SQL的是一个java.lang.Long型参数,
而resultType则定义我们需要返回的数据类型,这里为role,而role使我们之前注册的com.dumbo.pojo.Role

#{id} 为这条SQL的参数。而SQL列的别名和POJO的属性名称保持一致。
那么MyBatis就会把这条语句查询的结果自动映射到我们需要的POJO属性上,这就是自动映射。
可以用SqlSession来获取这个Mapper
用SqlSession来获取这个Mapper
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(1L);//执行方法
System.out.println(role.getRoleName());//打印角色名称
生命周期
SqlSessionFactoryBuilder
SqlSessionFactoryBuilder是利用XML或者Java编码获得资源来构建SqlSessionFactory的,通过它可以构建多个SessionFactory。
它的作用就是一个构造器,一旦构建了SqlSessionFactory,它的作用就已经完结,可以废弃回收了。
所以它的生命周期值存在于方法的局部,它的作用就是生成SqlSessionFactory对象。
SqlSessionFactory
SqlSessionFactory的作用是创建SqlSession,而SqlSession就是一个会话,相当于JDBC 的Connection对象。
每次应用程序需要访问数据库,就要通过SqlSessionFactory创建SqlSession,所以SqlSessionFactory应该在MyBatis应用的整个生命周期。
SqlSessionFactory的责任是唯一的,它的责任就是创建SqlSession,所以我们果断使用单例模式。
所以正确的做法是使得每一个数据库只对应一个SqlSessionFactory,管理好数据库资源的分配,编码过多的Connection被消耗。
SqlSession
SqlSession是一个会话,相当于JDBC 的一个Connection对象,它的生命周期应该是在请求数据库处理事务的过程中。
它是线程不安全的对象,在涉及多线程的时候我们需要特别当心。及时关闭。
它存活于一个应用的请求和操作,可以执行多条SQL,保证事务的一致性。
Mapper
Mapper是一个接口,而没有任何实现类,它的作用是发送SQL,然后返回需要的结果,或者执行SQL从而修改数据库的数据,因此他应该在SqlSession事务方法之内,是一个方法级别的东西。
它就如同JDBC 中的一条SQL语句的执行,他最大的范围和SqlSession是相同的。
尽量在一个SqlSession事务中的方法中使用它们,然后废弃掉。
Mapper各组件生命周期图

生命周期图

配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration> <!-- 配置 -->
	<properties/> <!-- 属性 -->
	<settings/> <!-- 设置 -->
	<typeAliases/> <!-- 类型名称 -->
	<typeHandlers/> <!-- 类型处理器 -->
	<objectFactory/> <!-- 对象工厂 -->
	<plugins/> <!-- 插件 -->
	<environments> <!-- 配置环境 -->
		<environment> <!-- 环境变量 -->
			<transactionManager/> <!-- 事物管理器 -->
			<dataSource/> <!-- 数据源 -->
		<environment>
	</environments>
	<databaseIdProvider/> <!-- 数据库厂商标识 -->
	<mappers/> <!-- 映射器 -->
</configuration>
properties元素
properties是一个配置属性的元素,让我们能在配置文件的上下文中使用它。
MyBatis提供3中配置方式:
    propertie子元素
    properties配置文件
    程序参数传递
propertie子元素
#propertie子元素配置:

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

#配置参数在配置文件中的使用:

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

properties配置文件
#数据库配置文件:

url=jdbc:mysql://localhost:3306/mybatis
driver=com.mysql.jdbc.Driver
username=root
password=123

#通过引用properties配置文件:

<properties resource="jdbc.properties"/>
程序参数传递
程序传递参数构建SqlSessionFactory

InputStream cfgStream = null;
Reader cfgReader = null;
InputStream proStream = null;
Reader proReader = 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.SEVERE,null,ex);
}
synchronized(CLASS_LOCK){
    if(SqlSessionFactory == null){
        //使用属性来创建SqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(cfgReader,properties);
    }
}
优先级
MyBatis支持的三种配置方式可能同时出现,并且属性会重复配置。

1. 在properties元素体内指定的属性首先被读取。
2. 根据properties元素中的resource属性读取类路径下属性文件,或者根据url属性指定的路径读取属性文件,并覆盖已读取的同名属性。
3. 读取作为方法参数传递的属性,并覆盖已读取的同名属性。

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

注意:
    1. 不要使用混合的方式,这样会使得管理混乱。
    2. 首选的方式是使用properties文件。
设置

settings配置属性

完整配置:

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="multipleResultSetsEnabled" value="true"/>
    <setting name="useColumnLabel" value="true"/>
    <setting name="useGeneratedKeys" value="false"/>
    <setting name="autoMappingBehavior" value="PARTIAL"/>
    <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
    <setting name="defaultExecutorType" value="SIMPLE"/>
    <setting name="defaultStatementTimeout" value="30"/>
    <setting name="defaultFetchSize" value="200"/>
    <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>
数据库设计采用下划线风格
javabean采用驼峰风格
不匹配的问题
开启下划线风格转变为驼峰的风格

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
别名
别名(typeAliases)是一个指代的名称。分为系统定义别名和自定义别名两类。
一个typeAliases的实例是在解析配置文件时生成的,然后长期保存在Configuration对象中,当我们使用它时,再把它拿出来,这样就没必要运行的时候再次生成它的实例了。
自定义别名
<!-- 定义别名 -->
<typeAliases>
    <typeAlias alias="girl" type="com.dumbo.pojo.Girl"/>
</typeAliases>
使用注解定义别名
@Alias("role")
public class Role{
    //some code
}
typeHandler 类型处理器
MyBatis在预处理语句(PreparedStatement)中设置一个参数时,或者从结果集(ResultSet)中取出一个值时,都会用注册了的typeHandler 进行处理。
typeHandler 常用的配置为Java类型(javaType)、JDBC类型(jdbcType)。
typeHandler的作用就是讲参数从javaType转化为jdbcType,或者从数据库取出结果时把jdbcType转化为javaType
ObjectFactory
当MyBatis在构建一个结果返回的时候,都会使用ObjectFactory(对象工厂)去构建POJO,在MyBatis中可以定制自己的对象工厂。
插件
插件(plugins)是比较复杂的,使用时要特别小心。使用插件将会覆盖一些MyBatis内部核心对象的行为。
environments 配置环境
配置环境可以注册多个数据源(dataSource),每一个数据源分为两大部分:一个是数据库源的配置,另外一个是数据库事务(transactionManager)的配置。
<environments default="dev">
    <environment id="dev">
        <!-- 采用JDBC事务管理 -->
        <transactionManager type="JDBC">
            <property name="autoCommit" value="false"/>
        </transactionManager>
        <!-- 配置数据库链接信息 -->
        <dataSource type="POOLED">
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <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属性时提供我们对数据库连接方式的配置
    (1) UNPOOLED,非连接池数据库(UnpooledDataSource)
    (2) POOLED,连接池数据库(PooledDataSource)
    (3) JNDI,JNDI数据源(JNDIDataSource)
    (4) 自定义数据源。
数据库事务
数据库事务 MyBatis是交由 SqlSession 去控制的,我们可以通过SqlSession提交(commit)或者回滚(rollback)。
# 数据库事务处理
try{
    sqlSession = SqlSessionFactoryUtil.openSqlSession();
    RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
    int count = roleMapper.insertRole(role);
    return count;
} catch (Exception e){
    sqlSession.rollback();
} finally {
    sqlSession.close();
}
数据源
UNPOOLED,非连接池,使用MyBatis提供的org.apache.ibatis.datasource.unpooled.UnpooledDataSource
POOLED,连接池,使用MyBatis提供的org.apache.ibatis.datasource.unpooled.PooledDataSource
JNDI,使用MyBatis提供的org.apache.ibatis.datasource.jndi.JndiDataSourceFactory来获取数据源。
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.apache.ibatis.datasource.DataSourceFactory;

public class DbcpDataSourceFactory extends BasicDataSource implements DataSourceFactory{
    private Properties props = null;
    
    @Override
    public void setProperties(Properties props){
        this.props = props;
    }
    
    @Override
    public DataSource getDataSource() {
        DataSource dataSource = null;
        
        try{
            dataSource = BasicDataSourceFactory.createDataSource(propd);
        } catch (Exception e){
            e.printStackTrace();
        }
        
        return dataSource;
    }
}
databaseIdProvider 数据库厂商标识
MyBatis提供默认的配置规则

<databaseIdProvider type="DB_VENDOR">
    <property name="SQL Server" value="sqlserver"/>
    <property name="MySQL" value="mysql"/>
    <property name="DB2" value="db2"/>
    <property name="Oracle" value="oracle"/>
</databaseIdProvider>
type="DB_VENDOR"是启动MyBatis内部注册的策略器。
首先MyBatis会将你的配置读入Configuration类里面,在连接数据库后调用 getDatabaseProductName()方法去获取数据库的信息,
然后用我们配置的name值去做匹配来得到DatabaseId。

获得数据库的ID 
sqlSessionFactory.getConfiguration().getDatabaseId();
定义数据库标签
<select parameterType="string" id="getRole" resultType="role" databaseId="mysql">
    select role_no as roleNo,role/-name as roleName,note from t_role where role_no = #{roleNo,javaType=String,jdbcType=VARCHAR}
</select>
如果没有配置databaseIdProvider 标签,那么database就会返回null。
如果配置了databaseIdProvider 标签,MyBatis就会用配置的name值去匹配数据库信息,如果匹配得上就会设置databaseId,否则依旧为null。
如果Configuration的databaseId 不为空,则它只会找到配置databaseId的SQL语句
MyBatis会加载不带databaseId属性和带有匹配当前数据库databaseId属性的所有语句。如果同时找到带有databaseId和不带databaseId的相同语句则后者会被舍弃。
引入映射器的方法
映射器是MyBatis最复杂、最核心的组件。
映射器命名空间对应的是一个接口的全路径。
# 定义Mapper接口
package com.dumbo.mapper;

import com.dumbo.pojo.Role;

public interface RoleMapper{
	public Role getRole(Long id);
}

# 定义Mapper 映射规则和SQL语句
<?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.dumbo.mapper.RoleMapper">
    <select id="getRole" parameterType="long" resultType="role">
		select id,role_name as rolename,note from role where id = #{id}
	</select>
</mapper>
# 1. 用文件路径引入映射器,即引入XML文件
<mappers>
    <mapper resource="com.dumbo.mapper.roleMapper.xml"/>
</mappers>

# 2. 通过引用一个包的方式引入映射器,以后只要在这个包下新建Mapper,不需要重新引入
<mappers>
    <package name="com.dumbo.mapper"/>
</mappers>

# 3. 用类注册应用映射器,通过接口的全限定名引入,必须保证接口和xml在同包之内
<mappers>
    <mapper class="com.dumbo.mapper.UserMapper" />
    <mapper class="com.dumbo.mapper.RoleMapper" />
</mappers>

# 4. 通过URL 协议:地址的方式引入映射器
<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最强大的工具
映射器的主要元素
元素名称 描述 备注
select 查询语句,最常用、最复杂的元素之一 可以自定义参数,返回结果集等
insert 插入语句 执行后返回一个整数,代表插入的条数
updata 更新语句 执行后返回一个整数,代表更新的条数
delete 删除语句 执行后返回一个整数,代表删除入的条数
parameterMap 定义参数映射关系 即将被删除的元素,不建议使用
sql 允许定义一部分SQL,然后在各个地方引用它 例如,一张表列名,我们可以一次定义,在多个SQL语句中使用
resultMap 用来描述从数据库结果集中加载对象,它是最复杂、最强大的元素 它将提供映射规则
cache 给定命名空间的缓存配置
cache-ref 其他命名空间的缓存配置的引用
select元素

select
select

# 简易数据类型的例子

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

# 在接口UserDAO中定义方法
public int countFirstName(String firstName);

操作步骤:
    id标出了这条SQL。
    parameterType定义参数类型
    resultType定义返回值类型
自动映射
有这样的一个参数autoMappingBehavior,当它不设置为NONE的时候,MyBatis会提供自动映射的功能,只要返回的SQL列名和JavaBean的属性一致,MyBatis就会帮助我们回填这些字段而无需任何配置

自动映射可以在settings元素中配置autoMappingBehavior属性值来设置其策略。
它包含三个值:
    NONE,取消自动映射。
    PARTIAL,只会自动映射,没有定义嵌套结果集映射的结果集。
    FULL,会自动映射任意复杂的结果集。
    
默认值为PARTIAL。所以在默认的情况下,它可以做到当前对象的映射,使用FULL是嵌套映射,在性能上会下降。
如果数据库是规范命名的,即每一个单词都用下划线分隔,POJO采用驼峰式命名方法,那么你也可以设置mapUnderscoreToCamelCase为true,这样就可以实现从数据库到POJO的自动映射了。
posted @ 2019-03-05 14:12  漠宇尘  阅读(127)  评论(0编辑  收藏  举报