MyBatis的核心配置
在使用MyBatis框架时,设计两个核心的d对象:SqlSessionFactory和SqlSession.
SqlsessionFactory
SqlSessionFactory是单个数据库映射关系经过编译后的内存镜像,其主要作用用来创建SqlSession对象,SqlSessionFactory实例对象是可以通过SqlSessionFactoryBulider对象来构建,而SqlSessionFactoryBulider对象可以通过XML文件或者Configuration实例来创建SqlSessionFactory实例,其代码如下:
//1.读取配置文件
String resource ="mybatis-config.xml"; InputStream inputStream=Resources.getResourceAsStream(resource);
//2.获取会话工厂对象
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
注意:SqlSessionFactory对象是线性安全的,它一旦被创建,在整个应用程序间都会存在,如果我们多次的创建同一个SqlSessionFactory对象,那么数据库的资源很快就会被应用完,为了解决这个问题,通常,一个数据库是建一个SqlSessionFactory对象的。
SqlSession
SqlSession对象是应用层和持久层之间进行数据库操作的一个单线程对象,其中主要作用是执行持久化操作,SqlSession对象中包含了所有执行数据库操作的方法,由于底层封装了JDBC的连接,所以可以直接使用SqlSession对象来执行已经映射的SQL语句。
注意:每一个线程都应该有自己的SqlSession实例,并且该SqlSession实例是不可共享的,同时,SqlSession是线程不安全的,因此,其使用范围最好是在一个请求中,或者一个方法中,绝对不能将其放入一个类的静态字段中,实例字段或者任何类型的管理范围中,使用完SqlSession后,要及时的关闭它,通常可以将其放入finally块中关闭。
Sqlsession sqlSession=sqlSessionFactory.openSession();
try{
//执行操作
}finally{
//关闭sqlSession
sqlSession.close();
}
使用工具类来创建SqlSession对象
由于每个方法执行都需要获取配置文件,并根据配置文件的信息来构建SqlSessionFactory对象,然后创建SqlSession对象,这导致了大量重复的代码,为了简化开发,可以将重复的代码封装到一个工具类中,然后通过这个工具类来创建SqlSession
package com.itheima.util;
/**
* 工具类
* @author 12428
*
*/
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.Null;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory=null;
//获取sqlSessionFactory对象
static {
try {
//使用MyBatis提供的Resource类加载配置文件
Reader reader =Resources.getResourceAsReader("mybatis-config.xml");
//构建SqlSessionFactory对象
sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
}catch(Exception e) {
e.printStackTrace();
}
}
//获取SqlSession对象的静态方法
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
二.配置文件
主要元素
在MyBatis核心配置文件中,
注意:
该元素是一个配置属性的元素,该元素通常是用于将内部的配置外在化,既通过外部的配置来动态的替换内部定义的属性。例如,数据库的来连接属性,就可以通过Java文件中配置文件来替换,具体如下:
1.在src下创建一个db.properties属性文件,内容如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=abc
2.在MyBatis配置文件mybatis-config.xml中的configuration元素中配置子元素
<properties resource="db.properties"/> //映入外部配置文件
3.修改
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
完成了上面的配置后,dataSource中连接数据库的4个属性,就可以由db.properties文件中的对应的值来动态的替换。
由于使用properties配置文件来配置属性值可以方便的在多个配置文件中使用这些属性,并且方便日后的维护和修改,所以在实际开发中,使用properties配置文件来配置属性值是最常用的方法。
元素
MyBatis在预处理语句(PrparedStatement)中设置了一个参数或者从结果集中取出一个值时,都会使用其框架内部的注册了的typeHandler(类型处理器)进行相关的处理,typeHandler是将预处理语句中传入的参数从javaType(java类型)装换为jdbcType(JDBC)类型,或者从数据库中取出结果时将jdbcType转换为javaType类型。MyBatis框架提供了一些默认的类型转换器,如果提供的类型转换器不能满足需求时,可以自定义类型转换器,自定义类型转换器可以通过实现TypeHandler接口或者继承BaseTypeHandle类来定义。
1.注册一个类的类型处理器:
<typeHandlers>
<!--以单个类的形式来配置:handler属性是用指定在程序中自定义的类型处理器类-->
<typeHandler handler="com.itheima.type.CustomtypeHandler"/>
</typeHandlers>
2.注册一个包中的所有类型处理器:
<typeHandlers>
<!--注册一个包中所有的typeHandler,系统会在启动时会自动扫描包下的所有文件-->
<package name="com.itheima.type"/>
</typeHandlers>
元素
在配置文件中,
使用该元素进行环境配置时的实例如下:
<!--因为一个environments元素中可以配置多个数据-库环境<environment>,default属性是指定使用哪个数据库环境,该属性值是<environment>元素的id值-><environments default="mysql">
<!-- 配置id为mysql的数据库环境 -->
<environment id="mysql">
<!-- 使用JDBC的事务管理 -->
<transactionManager type="JDBC"/>
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring"/>
<property name="username" value="root"/>
<property name="password" value="abc"/>
</dataSource>
</environment>
</environments>
对于数据源的配置,MyBatis框架提供了UNPOOLED,POOLED,JNDI这三种类型的数据源。
(1)UNPOOLED:配置此数据源后,在每次被请求时会打开和关闭连接,此配置适用于对性能没有要求的简单应用程序是一个很好的选择。
(2)POOLED:此数据源是利用”池“的概念将JDBC连接对象组织起来,避免了在创建新的实例时所需要初始化和认证的时间,这种方法使得并发web应用可以快速的响应,是当前流行的处理方法。
(3)JNDI:此数据源是可以在EJB或者应用服务器上使用,(是从TOMCAT内部来获取一个内置的数据库连接池)
<mappers>元素
在配置文件中,<mappers>元素是用来指定Mapper配置文件的位置,一般是使用如下四种方法引入:
1.使用类路劲引入
<mappers>
<mapper resource="com/itheima/mapper/UserMapper.xml"/>
</mappers>
2.使用本地文件路劲引入
<mappers>
<mapper url="file:///D:/com/itheima/mapper/UserMapper.xml"/>
</mappers>
3.使用接口类来引入
<mappers>
<mapper class="com.itheima.mapper.UserMapper"/>
</mappers>
4.使用包名来引入文件
<mappers>
<package name="com.itheima.mapper"/>
</mappers>
三.映射文件
映射文件是框架中的重要文件,可以说,此框架的强大之处就在于映射文件的编写上,
1.主要元素
在映射文件中,<mapper>元素是映射文件的根元素,其他元素都是它的子元素,
2.<select>元素
该元素是用于映射查询语句,它可以帮助我们从数据库中读取出数据,并组装数据库给业务开发人员
使用select元素执行查询操作非常简单,其示例如下
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer">
select * from t_customer where id=#{id}
</select>
select元素的常用属性如下:
属性
说明
id
表示命名空间中的唯一标识符,经常和命名空间namespace一起使用,组合namespace一起使用后如果不唯一,就会抛出错误。
parameterType
该属性是表示传入sql参数类的全限定名或者别名,它是一个可选属性。
resultType
该属性是表示从sql语句中返回结果的类型的全限定名或者别名,如果是集合类型,那么返回的应该是集合里可以包含的类型,而不是集合本身。
resultMap
该属性是表示外部resultMap的命名引用,返回时可以使用resultMap或者resultType
flushCache
表示在调用SQL语句后,是否清除缓之前查询的本地缓存和二级缓存,默认时false
useCache
用于控制二级缓存的开启和关闭,其值为布尔型,默认为true,表示将查询结果放在二级缓存里
timeout
用于设置超时参数,单位为秒,超时时将抛出异常
fetchSize
获取记录的总条数设置,其默认值是unset(依赖于驱动)
statementType
用于设置MyBatis使用哪个JDBC的Statement工作。
resultSetType
表示结果集的类型
3<insert>元素
insert元素是用于映射插入语句,在执行完元素中定义的SQL语句后,就会返回一个表示插入记录数的整数,insert元素的配置实例如下
<insert id="addCustomer" parameterType="com.itheima.po.Customer"
flushCache="true"
statmentType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
</insert>
insert元素的属性大部分和select相同,但是它由三个特定是属性,这三个属性如下:
属性
说明
keyProperty
(仅对insert和update有用)此属性的作用是将插入或者更新操作时的返回值赋给PO类的某个属性,通常会设置为主键对应的属性,如果需要设置联合主键,可以在多个值之间用逗号分开
keyColumn
(仅对insert和update有用)此属性的作用是用于设置第几行是主键,当主键列不是表中的第一列是,是需要设置这个属性,在需要使用主键联合时,值可以使用逗号分开
useGeneratedKeys
(仅对insert和update有用)此属性会使MyBatis使用JDBC的getGeneratedKeys()方法来获取由数据库内部产生的主键,如MYSql和sql Server等自动生成的主键
执行查询操作后,很多时候我们需要返回插入成功的数据生成的主键,此时就可以通过上面所讲解的3个属性来实现。
当使用的数据库支持自动增长时,我们可以通过keyproperty属性来指定PO类的某个属性接受主键的返回值,同时设置useGeneratedKeys的属性值为true,其使用如下:
<insert id="addCustomer" parameterType="com.itheima.po.Customer" keyProperty="id" useGeneratedKeys="true">
insert into t_customer(username,jobs,phone)
values(#{username},#{jobs},#{phone})
</insert>
使用以上的配置后执行插入操作后,就会返回插入成功的行数,以及插入行的主键值,为了验证配置,可以使用如下代码测试:
@Test
public void addCustomer(){
//获取SqlSession对象
SqlSession sqlSession=MyBatisUtis.getSession();
Customer customer=new Customer();
customer.setUsername("rose");
customer.setJobs("student");
customer.setPhone("11111111");
int rows=sqlSession.insert("som.itheima.mapper.CustomerMapper.addCustomer",customer);
//输出插入数据的主键
System.out.println(customer.getId());
if(rows>0){
system.out.println("您成功插入了"+rows+"行数据!");
}else{
system.out.println("插入失败!");
}
//执行提价事务
sqlSession.commit();
//关闭资源
sqlSession.close();
}
当数据库不可以支持自动增长时,如Oracle,或者自动增长的数据库取消了自动增长的规则时,可以使用MyBatis提供的另一种方法来自定义生成主键,具体配置如下:
<insert id="addCustomer" parameterType="com.itheima.po.Customer" >
<selectKey keyProperty="id" resultType="Integer" order="BEFORE">
select if(max(id) is null,1, max(id)+1) as newId from t_customer
</selectKey>
insert into t_customer(id,username,jobs,phone)
values(#{id},#{username},#{jobs},#{phone})
</insert>
在执行上面代码时,会先执行
selectKey可以设置的属性如下:
<selectKey
keyProperty="id"
resultType="Integer"
order="BEFORE"
statmentType="PREPARED"></selectKey>
order属性可以被设置为BEFORE或者AFTER,如果设置为BREFORE,那么它会先执行
4.
这两个元素的执行非常简单,它们的配置也基本相同,与
5.
<sql id="customerColumns">id,username,jobs,phone</sql>
引用此代码如下:
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer">
select <include refid="customerColumns"/>
from t_customer
where id=#{id}
</select>
使用
6.
该元素是用于配置查询返回的结果与JavaBean类之间的映射关系,是MyBatis中最强大的元素。它的主要作用是定义映射规则,级联的更新,以及定义类型转换器。
<!--resultMap元素的结构 -->
<resultMap type="" id="">
<!--类在实例化时,用来注入结果到构造方法中-->
<constructor>
<idArg/> <!--ID参数:标记结果作为Id-->
<arg/> <!--注入到构造方法中的一个普通结果-->
</constructor>
<id/> <!--用来表示哪个列示主键-->
<result> <!--注入到字段或者JavaBean属性的普通结果-->
<association property=""/> <!--用于一对一关联-->
<collection property=""/> <!--用于一对多关联-->
<discriminator javaType="">
<case value=""/> <!--基于某些值的结果映射-->
</discriminator>
</resultMap>
该元素的type属性是表示需要映射的POJO,id属性是这个resultMap的唯一标识,它的子元素
在默认的情况下,MyBatis程序在运行时会自动的将查询到 的结果和需要返回的对象的属性进行匹配复制(需要表中的列和对象的属性名完全一致。然而,在现实中,数据表中的列和需要返回的对象属性可能并不是完全一样,这时,就可以使用该元素进行处理。