1. 简介

Java程序都是通过JDBC连接数据库,但是只定义了接口规范,具体的实现交给各个数据库厂商去实现,因为每个数据库都有其特殊性。所以JDBC是一种桥接模式

这里为什么说JDBC是一种桥接模式呢?为例避免JDBC的缺陷出现了ORM模型,比如Hibernate,提供的是一种全表映射模型。因为Hibernate的一些缺陷,比如:

  • Hibernate屏蔽了SQL,只能全表映射,更新时需要发送所有的字段
  • 无法根据不同的条件组装不同的SQL
  • 对多表关联和复杂SQL查询支持较差,需要自己写SQL,返回后,需要自己将数据组装为POJO
  • 不能有效地支持存储过程
  • 虽然有HQL,但是性能较差。

因此出现了MyBatis,一个半自动的框架。之所以称之为半自动,是因为它需要手动提供POJO、SQL和映射关系,而全表映射的Hibernate只需要提供POJO和映射关系即可,因为Hibernate无需编写SQL,所以开发效率优于MyBatis。

2. MyBatis入门

MyBatis的核心组件:

  • SqlSessionFactoryBuilder(构造器):它会根据配置信息或者代码来生成SqlSessionFactory(工厂接口)
  • SqlSessionFactory:依靠工厂来生成SqlSession
  • SqlSession:是一个既可以发送SQL去执行并返回结果,也可以获取Mapper的接口
  • SQL Mapper:它是MyBatis新设计的组件,是由一个java接口和XML文件(或注解)构成的,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。

2.1 构建SqlSessionFactory

每个MyBatis的应用都是以SqlSessionFactory的实例为中心,可以通过SqlSessionFactoryBuilder获得,注意SqlSessionFactory是一个工厂接口而不是实现类,其任务是创建SqlSession。SqlSession类似于一个JDBC的Connection对象。MyBatis提供了两种模式去创建SqlSessionFactory:一种是XML配置的方式,另一种是代码方式。要尽量的使用配置文件,这样一方面可以避免硬编码,一方面方便日后配置人员修改。

org.apache.ibatis.session.Configuration在MyBatis中将以一个Configuration类对象的形式存在,存在于整个MyBatis应用的生命期中,以便重复读取和运用。我们可以一次性解析一次配置的XML保存到Configuration对象中。在MyBatis中提供了两个SqlSessionFactory的实现类,DefaultSqlSessionFactory和SqlSessionManager。目前使用的是DefaultSqlSessionFactory。

2.1.1 使用XML方式构建

这里以一个简易的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="role" type="com.learn.chapter2.po.Role"/>
</typeAliases>
<!--定义数据库信息,默认使用development数据库构建环境-->
<environments default="development">
<environment id="development">
<!--采用jdbc事务管理 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="false"/>
</transactionManager>
<!--配置数据库链接信息 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!--定义映射器 -->
<mappers>
<mapper resource="com/learn/chapter2/mapper/roleMapper.xml"/>
</mappers>
</configuration>

然后用代码实现创建SqlSessionFactory:

String resource="mybatis-config.xml";
InputStream inputStream=null;
inputStream=Resources.getResourceAsStream(resource);
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);

这里创建了一个XML文件输入流,用SqlSessionFactoryBuilder读取XML的信息 来创建SqlSessionFactory的对象。MyBatis的解析程序会将mybatis-config.xml文件配置信息解析到Configuration类对象里面,然后利用SqlSessionFactoryBuilder读取这个对象,为我们创建SqlSessionFactory。

2.1.2 使用代码方式构建

不推荐这种方式,因为修改环境的时候,要重新编译代码,不利于维护。

     //构建数据库连接池
PooledDataSource dataSource=new PooledDataSource();
dataSource.setDriver("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
dataSource.setUsername("root");
dataSource.setPassword("root");
//构建数据库事务方式
TransactionFactory transactionFactory=new JdbcTransactionFactory();
//创建数据库运行环境
Environment environment=new Environment("development",transactionFactory,dataSource);
//构建Configuration对象
Configuration configuration=new Configuration(environment);
//注册一个MyBatis上下文别名
configuration.getTypeAliasRegistry().registerAlias("role",Role.class);
//加入一个映射器
configuration.addMapper(RoleMapper.class);
//使用SqlSessionFactoryBuilder构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(configuration);
return sqlSessionFactory;

采用代码方式一般是需要加入自己特性的时候才会用到,例如数据源配置的信息要求是加密的时候,我们需要把它转化出来。大部分情况下不建议用这个方式来创建SqlSessionFactory

2.1.2 创建SqlSession

在MyBatis中SqlSession接口的实现类有两个,分别是DefaultSqlSession和SqlSessionManager。我们构建了SqlSessionFactory,然后生成门面接口SqlSession。SqlSession接口类似于一个JDBC中的Connection接口对象,我们需要保证每次用完正确关闭它。

SqlSession的用途主要是获取映射器以及直接通过命名信息去执行SQL返回结果。

2.1.3 映射器

由Java接口和XML文件(或注解)共同组成,作用如下:

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

使用XML文件配置方式实现Mapper,第一步给出Java接口:

public interface RoleMapper {
public Role getRole(Long id);
public int deleteRole(Long id);
public int insertRole(Role role);
}

第二步给出一个映射文件:

<?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.chapter2.mapper.RoleMapper">
<select id="getRole" resultType="role" parameterType="long">
select id,role_name as roleName,note from t_role where id=#{id}
</select>
</mapper>
  • MyBatis会读取这个配置文件,生成映射器
  • 定义一个命名空间为com.learn.chapter2.mapper.RoleMapper的SQL Mapper,这个命名空间和我们定义的接口的全限定名要一致
  • 用一个select元素定义一个查询SQL,id是getRole,和我们接口中的方法名是一致的
  • #{id}为这条SQL的参数。而SQL列的别名和POJO的属性名称保持一致。那么MyBatis就会把这条语句查询的结果自动映射到我们需要的POJO属性上

现在可以使用SqlSession来获取这个Mapper:

RoleMapper roleMapper=sqlSession.getMapper(RoleMapper.class);
Role role=roleMapper.getRole(1L);

2.1.4 Java注解方式实现Mapper

不推荐注解的方式,如果系统简单的话,使用注解方式也不失为一个好办法。

注册这个接口为映射器:

2.1.4 一些疑问

这要注意的是在MyBatis中保留这iBatis,通过命名空间+SQL id 的方式发送SQL并返回数据的形式,而不需要获取映射器:

2.2 生命周期

SqlSessionFactoryBuilder:只存在于方法的局部,作用是生成SessionFactory对象。

SqlSessionFactory:存在于MyBatis应用的整个生命周期中,唯一责任是创建SqlSession,要采用单例模式。

SqlSession:一个会话,相当于JDBC的一个Connection对象,他的生命周期应该是在请求数据库处理事务的过程中。它是一个线程不安全的对象。

Mapper:一个接口,没有任何实现类,作用是发送SQL。因此它应该在一个SqlSession事务方法之内,是一个方法级别的东西。

2.3 实例

代码清单2-11:log4j.properties

log4j.rootLogger=DEBUG, stdout
log4j.logger.org=BEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: m%n

其中参数的解释见博文:http://www.cnblogs.com/alipayhutu/archive/2012/06/21/2558249.html

其次,构建SessionFactory,我们需要配置文件,代码:

<?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="role" type="com.learn.chapter2.po.Role"/>
</typeAliases>
<!--定义数据库信息,默认使用development数据库构建环境-->
<environments default="development">
<environment id="development">
<!--采用jdbc事务管理 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="false"/>
</transactionManager>
<!--配置数据库链接信息 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!--定义映射器 -->
<mappers>
<mapper resource="com/learn/chapter2/mapper/roleMapper.xml"/>
</mappers>
</configuration>

构建SqlSessionFactory

package com.learn.chapter2.util;

import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger; import org.apache.commons.logging.Log;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class SqlSessionFactoryUtil {
//SqlSessionFactory对象
private static SqlSessionFactory sqlSessionFactory=null;
//类线程锁
private static final Class Class_LOCK=SqlSessionFactoryUtil.class;
/**
* 私有化构造参数
*/
private SqlSessionFactoryUtil(){} /**
* 构建SqlSessionFactory
*/
public static SqlSessionFactory initSqlSessionFactory(){
String resource="mybatis-config.xml";
InputStream inputStream=null;
try{
inputStream=Resources.getResourceAsStream(resource);
}catch (Exception e) {
Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE, null,e);
}
synchronized (Class_LOCK) {
if(sqlSessionFactory==null){
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
}
return sqlSessionFactory;
}
/**
* 打开SqlSession
*/
public static SqlSession openSqlSession(){
if(sqlSessionFactory==null){
initSqlSessionFactory();
}
return sqlSessionFactory.openSession();
}
}

上面要注意的部分:

1. 类线程锁:private static final Class Class_LOCK=SqlSessionFactoryUtil.class;

实现一个POJO类——Role.java

package com.learn.chapter2.po;

public class Role {
private Long id;
private String roleName;
private String note;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}

还需要一个映射器的描述:

<?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.chapter2.mapper.RoleMapper">
<select id="getRole" resultType="role" parameterType="long">
select id,role_name as roleName,note from t_role where id=#{id}
</select>
<insert id="insertRole" parameterType="role">
insert into t_role(role_name,note) values (#{roleName},#{note})
</insert>
<delete id="deleteRole" parameterType="long">
delete from t_role where id=#{id}
</delete>
</mapper>

定义相应的接口:

package com.learn.chapter2.mapper;

import com.learn.chapter2.po.Role;

public interface RoleMapper {
public Role getRole(Long id);
public int deleteRole(Long id);
public int insertRole(Role role);
}

使用一个main方法来测试:

package com.learn.chapter2.main;

import org.apache.ibatis.session.SqlSession;

import com.learn.chapter2.mapper.RoleMapper;
import com.learn.chapter2.po.Role;
import com.learn.chapter2.util.SqlSessionFactoryUtil; public class Chapter2Main {
public static void main(String[] args){
SqlSession sqlSession=null;
try{
sqlSession=SqlSessionFactoryUtil.openSqlSession();
RoleMapper roleMapper=sqlSession.getMapper(RoleMapper.class);
Role role=new Role();
role.setRoleName("testName");
role.setNote("testRole");
roleMapper.insertRole(role);
roleMapper.deleteRole(1L);
sqlSession.commit();
}catch (Exception e) {
System.err.println(e.getMessage());
sqlSession.rollback();
}finally{
if(sqlSession!=null){
sqlSession.close();
}
}
}
}

《深入浅出MyBatis技术原理与实战》——1.简介,2.入门的更多相关文章

  1. 《深入浅出MyBatis技术原理与实战》——6. MyBatis的解析和运行原理

    MyBatis的运行分为两大部分,第一部分是读取配置文件缓存到Configuration对象,用以创建SqlSessionFactory,第二部分是SqlSession的执行过程. 6.1 涉及的技术 ...

  2. 《深入浅出MyBatis技术原理与实战》——7. 插件

    在第6章讨论了四大运行对象的运行过程,在Configuration对象的创建方法里我们看到了MyBatis用责任链去封装它们. 7.1 插件接口 在MyBatis中使用插件,我们必须使用接口Inter ...

  3. 《深入浅出MyBatis技术原理与实战》——4. 映射器,5. 动态SQL

    4.1 映射器的主要元素 4.2 select元素 4.2.2 简易数据类型的例子 例如,我们需要统计一个姓氏的用户数量.应该把姓氏作为参数传递,而将结果设置为整型返回给调用者,如: 4.2.3 自动 ...

  4. 深入浅出MyBatis技术原理与实战

    第1 章 MyBatis 简介..................................................................................... ...

  5. 《深入浅出MyBatis技术原理与实战》——3. 配置

    要注意的是上面那些层次是不能够颠倒顺序的,否则MyBatis在解析文件的时候就会出现异常. 3.1 properties元素 properties是一个属性配置元素,让我们能在配置文件的上下文中使用它 ...

  6. 深入浅出Mybatis技术原理与实战(杨开振)(带详细书签) PDF 下载 高清 完整版+源码

    (杨开振) 源码 IDE eclipse 建表语句也在里面 电子书+源码地址

  7. 2017.2.9 深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二)-----配置文件详解

    深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二) ------配置文件详解 8.2 MyBatis-Spring应用 8.2.1 概述 本文主要讲述通过注解配置MyBa ...

  8. 2MyBatis入门--深入浅出MyBatis技术原理与实践(笔记)

    什么是 MyBatis ? MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis ...

  9. 3MyBatis配置--深入浅出MyBatis技术原理与实践(笔记)

    XML 映射配置文件 configuration 配置 properties 属性 settings 设置 typeAliases 类型命名 typeHandlers 类型处理器 objectFact ...

随机推荐

  1. AES encryption of files (and strings) in java with randomization of IV (initialization vector)

    http://siberean.livejournal.com/14788.html Java encryption-decryption examples, I've seen so far in ...

  2. 使用httpclient post请求中文乱码解决办法

    使用httpclient post请求中文乱码解决办法   在使用httpclient发送post请求的时候,接收端中文乱码问题解决. 正文: 我们都知道,一般情况下使用post请求是不会出现中文乱码 ...

  3. ZooKeeper分层次的法定人数(十二)

    分层次的法定人数的介绍 这个文档给出一个关于怎么使用分层次的法定人数的例子.基本思路是很简单的.首先,我们把服务端分组,然后每一组一行.下一步我们分配一个权重为每一个服务端. 下面的例子展示了怎么每组 ...

  4. 其他:OI竞赛中的文件操作

    本文介绍三种方法进行文件输入输出,都非常实用 第一种方法是采用重定向的形式进行输入输出,很方便 freopen("input.txt","r",stdin); ...

  5. HDU 1874 SPFA/Dijkstra/Floyd

    这题作为模板题,解法好多... 最近周围的人都在搞图论阿,感觉我好辣鸡,只会跟风学习. 暂时只有SPFA和Dijkstra的 SPFA (邻接表版.也可以写成临接矩阵存图,但题目可能给出平行边的,所以 ...

  6. jsp05 指令与动作

    JSP7个动作指令如下 : jsp:forward: 执行页面转向,将请求的处理转发到下一个页面. jsp:param: 用于传递参数,必须与其他支持参数曲标签一起使用. jsp:include: 用 ...

  7. [BZOJ2440]完全平方数解题报告|莫比乌斯函数的应用

    完全平方数 小 X 自幼就很喜欢数.但奇怪的是,他十分讨厌完全平方数.他觉得这些数看起来很令人难受.由此,他也讨厌所有是完全平方数的正整数倍的数.然而这丝毫不影响他对其他数的热爱.  这天是小X的生日 ...

  8. 【BZOJ】1776: [Usaco2010 Hol]cowpol 奶牛政坛

    [题意]给定n个点的树,每个点属于一个分类,求每个分类中(至少有2个点)最远的两点距离.n<=200000 [算法]LCA [题解]结论:树上任意点集中最远的两点一定包含点集中深度最大的点(求树 ...

  9. c语言目录操作总结

    =================================================== char *getcwd( char *buffer, int maxlen ); (获取当前目 ...

  10. POJ 3276 Face The Right Way (尺取法)

    题目链接 Description Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are f ...