声明:本人通过《深入浅出MyBatis技术原理与实战》来完成学习并总结如文.
Hibernate的相关缺点
1. 全表映射带来的带来的不便,更新要发送所有字段
2. 无法根据不同条件组装SQL
3. 对多表关联和复杂SQL查询支持较差,需要自己写SQL,返回后需要自己将数据组装成POJO
4. 不能有效支持存储过程
5. 性能差,无法做到SQL优化
# POJO:Plain Ordinary Java Objecdt数据库的表和简单JAVA对象的映射关系模型
mybatis
简单介绍:
mybatis是一个基于JAVA的持久层框架。与Hibernate的不同是:除了提供映射文件,还需要提供SQL语句。mybatis提供的映射文件主要包含以下三个部分:
- SQL
- 映射规则
- POJO
mybatis的核心组件:
- SqlSessionFactoryBuilder(构造器):根据配置信息或代码来生成SqlSessionFactory(工厂接口)
- 实现方式:
String resource = "mybatis-config.xml";
InputStream inputStream = Resource.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = null;
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
- SqlSessionFactory:打开SqlSession(会话)
- 实现方式:
SqlSession sqlSession = null;
try{
sqlSesssion = sqlSessionFactory.openSesson();
//And code you need
sqlSession.commit();
}catch(Exception e){
e.printStackTrace();
}finally{
if(sqlSession != null){
sqlSession.close();
}
}
- SqlSession:一个发送SQL去执行得到返回结果,并且获取Mapper的接口
- 类似于前台的一个作用,我们把信息(功能、参数)交给前台(Session),然后前台返回我们需要的结果(Result)。它类似于JDBC里的Connection,当我们完成操作后,需要显示关闭它
- MyBatis中的SqlSession接口有两种:
- DefaultSqlSession
- SqlSessionManager
- SQL Mapper:由一个Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则。负责发送SQL去执行,并返回结果。
简单实现过程:
- 创建SqlSessionFactory
- 形象化的说法通过一个工厂建造工具来建造一个工厂,这个工具就是上面说的SqlSessionFactoryBuilder
- 有两种建造方式:一种通过XML,一种通过JAVA代码,mybatis-config.xml代码的配置,不做赘述,玩家可以自己去搜索
- 通过SqlSessionFactory提供一个SqlSession
打开Session的一般方式正如上文所说,而关于Session的具体用途主要有一下两种:
- 获取映射器,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据执行并返回结果。
- 直接通过命名信息去执行SQL返回结果,在SqlSession层可以通过update、insert、select、delete等方法,带上SQL的id来操作在XML中配置好的SQL;也支持事务,通过commit、rollback方法提交或者回滚事务。
- 通过Mapper来映射数据库项和Java对象,也就是所谓的映射器(映射器是Mybatis的核心内容)
映射器主要是由Java接口和XML文件共同组成,它(映射器)主要有这样几个功能:
- 定义参数类型
- 描述缓存
- 描述SQL语句
- 定义查询结果和POJO的映射关系
关于映射器的实现,主要也有两种方式:
- XML文件方式:在mybatis-config.xml文件中通过如下语句描述了一个xml
<mappers> <mapper resource = "com/blaze/mybatis_try/mapper/Mapper.xml/> </mapper>
它是用来生成Mapper的。
- 代码方式:主要是通过在Configuration里面注册Mapper接口,并且写入Java注解。(关于这种方式,各位同学可以自行搜索了解)
关于映射器实现方式的选择,原书作者给了如下建议:
强烈建议选择XML的方式实现,理由如下:
- SQL很复杂条件很多的情况下,写在Java文件里可读性较差,增加维护成本
- 功能不对等,Java注解是受限的而且功能有限,但是Mybatis的Mapper内容相当多而且复杂,并且在功能上非常强大,使用Java注解的方式,对Mybatis的灵活性和功能都会有所损耗。而选择XML实现方式,可以带来更为灵活的空间,体验Mybatis功能的强大和灵活。
核心组件的生命周期
理解生命周期的理由:如果不正确理解Mybatis组件的生命周期可能带来很严重的并发问题,影响对Mybatis应用的正确性和高性能。
- SqlSessionFactoryBuilder
SqlSessionFactoryBuilder的作用就是通过XML或者Java代码来建造一个工厂(SqlSessionFactory),并且可以通过它建造多个这样的工厂。一旦完成建造工厂的任务,我们就应该废弃它,回收空间。所以它的生命周期只存在方法局部,完成工厂的建造即结束。
- SqlSessionFactory
SqlSessionFactory的作用就是创建会话(SqlSession),相当于JDBC的Connection连接。每当我们需要访问数据库时,就要通过SqlSessionFactory创建会话,所以SqlSessionFactory的生命周期应该是整个Mybatis的生命周期。但是如果打开过多的SqlSession,就相当于JDBC创建了过多的Connection,那么连接资源就会很快被耗尽,所以对于每一个数据库,只对应一个SqlSessionFactory,以此来管理数据资源的分配,防止连接资源被过度消耗。
- SqlSession
SqlSession相当于JDBC的connnection,生命周期应该是在请求数据库处理事务的过程中,它存活于一个应用的请求和操作,可以执行多个SQL,保证事务的一致性。此外,它还是个线程不安全的对象,在多线程中应当注意数据库的隔离级别和数据库锁等高级特性。并且当SqlSession完成自身工作时需要及时关闭,以防止数据库连接池的活动资源减少,影响系统性能。
- Mapper
Mapper是一个接口,没有任何实现类,作用是发送SQL,返回所需结果。所以它的生命周期应该在一个SqlSession事务方法之内,是一个方法级别的东西,一旦完成一个事务的操作,即可废弃。
配置
# Mybatis的配置文件对整个Mybatis体系有着很重要的作用,而且具有规定的层次,这些层次是不能随意点到顺序的,颠倒顺序会导致Mybatis在解析XML时出现异常。
Mybatis配置文件层次结构
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--配置-->
<properties/><!--属性-->
<setting/><!--设置-->
<typeAliases/><!--类型别名-->
<typeHanlders/><!--类型处理器-->
<objectFactory/><!--对象工厂-->
<plugins/><!--插件-->
<environments><!--配置环境-->
<environment><!--环境变量-->
<transactionManager/><!--事务管理器-->
<dataSource/><!--数据源-->
</environment>
</environments>
<databaseIdProvider/><!--数据库厂商标识-->
<mapper/><!--映射器-->
</configuration>
properties元素
Mybatis提供三种配置方式:
- property子元素
- 首先在属性标签中进行配置:
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
</properties>
2. 然后可以再dataSource中使用配置好的属性值,例如:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
</dataSource>
- properties配置文件
- 首先写properties配置文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
2.再mybatis-config.xml中进行导入:
<properties resource="jdbc.properties"/>
-
程序参数传递
- 使用理由:
实际工作中,系统是由运维人员配置,生产数据库的用户密码对于开发者而言是保密的,为了系统的安全,运维人员要求对配置文件中的数据库用户和密码进行加密,这样我们的配置文件中往往配置的事加密过后的数据库信息,这个时候只能用编码的方式来传递我们所需要的数据库信息。
- 假设jdbc.properties的username和password两个属性使用了加密的字符串,首先需要在生成SqlSessionFactory之前,将所需信息转换为明文,接下来使用系统提供的decode(str)方法
InputStream cfgStream = null; Reader cfgReader = null; InputStream proStream = null; Reader proReader = null; Properties properties = null; try{ //读入配置文件流 cfgStream = Resources.gerResourceAsStream("mybatis-confg.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"))); }
作者建议:
注意点:当这三种方式同时应用在一次配置中时,第一种方式下的配置信息首先被读取出来,然后再通过第二种方式读取配置信息,并且覆盖已经被读取出的同名属性,最后才对使用第三种方式的配置信息进行读取,并继续产生覆盖。所以通过第三种方式创建的配置信息具有最高优先级。
在实际的操作中,主要注意以下2点:
- 不要使用混合的方式来对配置信息进行声明
- 首选第一种方式
如果我们需要对其进行加密或者其他加工以满足特殊的要求,建议使用第三种方式。可以使配置都来自于同一个配置文件,不容易产生没有必要的歧义,同时方便管理
设置(settting)
一般情况下我们都不需要去配置它,或者只需要配置少数几项,由于表格过于庞大,还请读者自己动手去查阅mybatis配置文件相关设置配置信息。