天天看点

认识Mybatis核心组件

持久层可以将业务数据存储到磁盘,具备长期存储能力,只要磁盘不损坏(大部分的重要数据都会有相关的备份机制),在断电或者其他情况下,重新开启系统仍然可以读取这些数据。Mybatis 最大的成功主要有三点:

  • ·不屏蔽 SQL 意味着可以更为精确地定位 SQL 语句,可以对其进行优化和改造,
  • ·提供强大、灵活的映射机制 ,方便 Java 开发者使用 。
  • 提供了使用 Mapper 的接口编程,只要 个接口和 XML 就能创建映射器

1. Mybatis的核心组件

核心组件分为四个部分:

  • SqlSessionFactoryBuilder (构造器):它会根据配置或者代码来生成SqISessionF actory ,采用的是分步构建的Builder 模式。
  • SqlSessionFactory (工厂接口):依靠它来生成 Sq!Session 使用的是工厂模式。
  • SqlSession 会话〉: 既可以发送 SQL 执行返回结果,也可以获取 Mapper的接口。
  • SQL Mapper (映射器): MyBatis 新设计存在的组件,它由 Java 接口和 XML文件(或注解〉构成,需要给出对应的SQL 和映射规则。它负责发送 SQL 去执行,并返回结果。
  • 认识Mybatis核心组件

2. SqlSessionFactory

MyBatis 中,既可以通过读取配置的 XML 文件的形式生成 Sq!SessionFactory ,也可以通过 Java 代码的形式去生成 SqlSessionFactory 。

当配置了 XML 或者提供代码后, MyBatis 会读取配置文件,通过Configuration 类对象构建整个 MyBatis 的上下文。SqlSessionFactory是一个接口,在MyBatis 中它存在两个实现类 SqlSessionManager DefaultSqlSessionFactory。

认识Mybatis核心组件

2.1 使用XML构建SqlSessionFactory

在 MyBatis 中的 XML 分为两类,一类是基础配置文件,通常只有 1个,主要是配置 些最基本的上下文参数和运行环境 ;另一类是映射文件,它可以配置映射关系、SQL 参数等信息。

基础配置文件:

认识Mybatis核心组件
认识Mybatis核心组件
  • <typeAlias>元素定义了 个别名 role它代表着com.leam.ssm.chapter3.pojo.Role这个类。这样定义后,在 MyBatis

    上下文中就可以使用别名去代替全限定名了。

  • <env ironment>

    ;元素的定义,这里描述的是数据库,

    <transactionManager>

    元素是配置事务管理器。然后采用

    <dataSource>

    元素配置数据库.属性type=”POOLED”代表采用 MyBatis 部提供的连接池方式。
  • <mapper>

    元素代表引入的那些映射器。

使用XML构建SqlSessionFactory:

认识Mybatis核心组件

先读取 mybatis-config.xml 然后通过 Sq!SessionFactoryBuilder的 Builder 方法去创建SqlSessionFactory。

2.2 使用代码创建SqlSessionFactory

认识Mybatis核心组件

3. SqlSession

MyBatis 中, SqlSession 是其核心 。在 MyBatis 中有两个实现类DefaultSqlSession和SqlSessionManager。DefaultSqlSession 是单线程的,而 SqlSessionManager 在多线程环境下使用。SqlSession 的作用 类似JDBC中的Connection 对象,代表着一个连接资源的启用。作用如下:

  • 获取 Mapper 接口。
  • 发送 SQL 给数据库。
  • 控制数据库事务。

创建SqlSession:

认识Mybatis核心组件

注意, SqlSession 只是 个门面接口,它有很多方法,可以直接发送 SQL 。它就好像软件公司的商务人员,是 个门面,而实际干活的是软件工程师。在 MyBatis ,真正干活的是 Executor。

SqlSession控制数据库事务:

认识Mybatis核心组件

这里使用 commit 方法提交事务,或者使用 rollback 方法回滚事务。因为它代表着数据库的连接资源,使用后要及时关闭它,如果不关闭,那么数据库的连接资源就会很快被耗费光,整个系统就会陷入瘫痪状态,所以用 finally 语句保证其顺利关闭。

4. 映射器

映射器是 MyBatis 中最重要、最复杂的组件,它由1个接口和对应的 XML 文件(或注解〉组成。可以配置以下内容:

描述映射规则;提供SQL语句,配置SQL参数类型、返回类型、缓存;配置缓存、提供动态SQL。

映射器 主要作用就是将 SQL 查询到的结果映射为 POJO ,或者将 POJO 的数据插入到数据库中 并定义 些关于缓存等的重要内容。

定义pojo:

认识Mybatis核心组件

4.1 使用XML实现映射器

XML 定义映射器分为两个部分: 接口和 XML 。先定义 个映射器接口:

认识Mybatis核心组件

在用 XML 方式 创建SqISession 配置文件中有这样段代码:

认识Mybatis核心组件

它的作用就是引入 XML 。用 XML 方式创建映射器。

认识Mybatis核心组件
认识Mybatis核心组件

有了这两个文件,就完成了 个映射器的定义。

  • <mapper>元素中的属性 namespace 所对应的是个接口的全限定名,于是 MyBatis上下文就可以通过它找到对应的接口。
  • <select>

    元素表明这是 条查询语旬 而属性 id 标识了这条 SQL ,属性 parameterType=" long,说明传递给 SQL 的是 long 参数, resultType=“role” 表示返回的是 role 类型的返回值。role是之前配置文件 mybatis-config.xml 配置的别名,指代的是 com leam.ssm.chapter3.pojo.Role。
  • SQL中的#{id}表示传递进去的参数

4.2 注解实现映射器

它只需要 个接口就可以通过 MyBati 的注解来注入 SQL。

认识Mybatis核心组件

4.3 SqlSession发送SQL

有了映射器就可以通过SqlSession发送SQL了。例如:

认识Mybatis核心组件

selectOne 方法表示使用查询并且只返回一个对象 ,而参数是一个String对象和一个Object对象。这里是一个long参数, long 参数是它的主键。

String对象是由命名空间加上SQLid 组合而成的,它完全定位了一条SQL, 这样MyBatis就会找到对应的SQL。

4.4 使用Mapper接口发送SQL

SqlSession可以获取Mapper接口,通过Mapper接口发送SQL:

认识Mybatis核心组件

SqlSession的getMapper方法来获取一个Mapper接口,可以调用它的方法。XML文件或接口注解定义的SQL都可以通过“类的全限定名+方法名”查找。

5. 生命周期

所谓生命周期就是每 个对象应该存活的时间,比如一些对象一次用完后就要关闭,使它们被 Java 虚拟机销毁,以避免继续占用资源,所以我们会根据每 个组件的作用去确定其生命周期。

5.1 SqlSessionFactoryBuilder

作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 Sq!SessionFactory 的方法中,而不要让其长期存在。

5.2 SqlSessionFactory

SqlSessionFactory 可以被认为是 个数据库连接池,它的作用是创建 SqlSession 接口对象。由于MyBatis本质是Java对数据库的操作,所以SqlSessionFactory 的生命周期存在于整个 MyBatis 应用之中,一旦创建了SqlSessionFactory 就要长期保存它,直至不再使用 MyBatis应用。

由于 qlSessionFactory是个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory ,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机,因此一般SqlSessionFactory都是一个单例,在应用中被共享。

5.3 SqlSession

如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相 当于一个数据库连接(Connection对象),可以在一个事务里面执行多条 SQL ,然后通过它的 commit、rollback 等方法 提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪。

5.4 Mapper

Mapper 是一个接口,它由 SqlSession 所创建,所以它的最大生命周期至多和 SqlSession保持一致,尽管它很好用,但是由于 SqlSession 关闭,它的数据连接资源也会消失,它的生命周期应该小于等于 Sq!Se ssion 的生命周期 。Mpper 代表的是 个请求中的业务处理,所以它应该在一个请求中,一旦处理完了相关的业务,就应该废弃它。

认识Mybatis核心组件

6. 实例

通过一个实例对以上内容进行综合。

认识Mybatis核心组件

首先创建一个POJO对象:

package com.learn.ssm.chapter3.pojo;

public class Role {

	private Long id;
	private String roleName;
	private String note;

	/** setter and getter **/
	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方式构建映射器,包含一个接口和XML文件,实现增删改查,因此定义一个接口:

package com.learn.ssm.chapter3.mapper;
import java.util.List;
import com.learn.ssm.chapter3.pojo.Role;
public interface RoleMapper {
	public int insertRole(Role role);
	public int deleteRole(Long id);
	public int updateRole(Role role);
	public Role getRole(Long id);
	public List<Role> findRoles(String roleName);
}
           

insertRole表示插入一个Role对象,deleteRole是删除,updateRole为修改一个Role对象,getRole为获取一个Role对象,findRoles为通过角色名称获得一个角色对象列表。同时创建一个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.ssm.chapter3.mapper.RoleMapper">

	<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>

	<update id="updateRole" parameterType="role">
		update t_role set role_name = #{roleName}, note = #{note} where id= #{id}
	</update>

	<select id="getRole" parameterType="long" resultType="role">
		select id,
		role_name as roleName, note from t_role where id = #{id}
	</select>

	<select id="findRoles" parameterType="string" resultType="role">
		select id, role_name as roleName, note from t_role
		where role_name like concat('%', #{roleName}, '%')
	</select>
</mapper>
           

这是一些较简单的 SQL 语旬 insert delete select update 元素代表了增、删、改、查,而它里面的元素 id 标识了对应 SQL。parameterType 了是什么类型参数,resultType 代表结果映射成为什么类型。其中 insert delete update 返回 的都是影响条数。

接着构建SqlSessionFactory。完成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="role" type="com.learn.ssm.chapter3.pojo.Role"/>
  </typeAliases>
  <!-- 数据库环境 -->
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/chapter3"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 映射文件 -->
  <mappers>
    <mapper resource="com/learn/ssm/chapter3/mapper/RoleMapper.xml"/>
    <mapper class="com.learn.ssm.chapter3.mapper.RoleMapper2"/> 
  </mappers>
</configuration>
           

使用 mybatis-config.xml 文件,通过 SQLSessionFactoryBuilder 来构建 SqlSessionFactory。由于 SqISessionFactory应该采用单例模式,所以这里使用单例模式去构建它。SqlSessionFactory如下:

package com.learn.ssm.chapter3.utils;

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

import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import com.learn.ssm.chapter3.mapper.RoleMapper;
import com.learn.ssm.chapter3.mapper.RoleMapper2;
import com.learn.ssm.chapter3.pojo.Role;

public class SqlSessionFactoryUtils {

	private final static Class<SqlSessionFactoryUtils> LOCK = SqlSessionFactoryUtils.class;

	private static SqlSessionFactory sqlSessionFactory = null;

	private SqlSessionFactoryUtils() {
	}

	public static SqlSessionFactory getSqlSessionFactory() {
		synchronized (LOCK) {
			if (sqlSessionFactory != null) {
				return sqlSessionFactory;
			}
			String resource = "mybatis-config.xml";
			InputStream inputStream;
			try {
				inputStream = Resources.getResourceAsStream(resource);
				sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			} catch (IOException e) {
				e.printStackTrace();
				return null;
			}
			return sqlSessionFactory;
		}
	}
	
	
	//��������SqlSessionFactory
	public static SqlSessionFactory getSqlSessionFactory2() {
		synchronized (LOCK) {
			//���ݿ����ӳ���Ϣ
			PooledDataSource dataSource = new PooledDataSource();
			dataSource.setDriver("com.mysql.jdbc.Driver");
			dataSource.setUsername("root");
			dataSource.setPassword("123456");
			dataSource.setUrl("jdbc:mysql://localhost:3306/chapter3");
			dataSource.setDefaultAutoCommit(false);
			//����MyBatis��JDBC����ʽ
			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);
			configuration.addMapper(RoleMapper2.class);
			//ʹ��SqlSessionFactoryBuilder����SqlSessionFactory
			sqlSessionFactory = 
			    new SqlSessionFactoryBuilder().build(configuration);
			return sqlSessionFactory; 	
		}
	}

	public static SqlSession openSqlSession() {
		if (sqlSessionFactory == null) {
			getSqlSessionFactory();
		}
		return sqlSessionFactory.openSession();
	}
}
           

构造方法中加入了 private 关键字, 其他代码不能通过 new 方式来创建它。synchronized 关键字加锁 主要是为了防止在多线程中多次实例化SqlSessionFactory对象,从而保证 SqlSessionFactory 的唯一性,openSqlSession方法的作用则是创建SqlSession对象。

程序的启动代码:

package com.learn.ssm.chapter3.main;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import com.learn.ssm.chapter3.mapper.RoleMapper;
import com.learn.ssm.chapter3.mapper.RoleMapper2;
import com.learn.ssm.chapter3.pojo.Role;
import com.learn.ssm.chapter3.utils.SqlSessionFactoryUtils;
public class Chapter3Main {

	public static void main(String[] args) {
		testRoleMapper();
		testRoleMapper2();
		
	}
	
	
	private static void testRoleMapper() {
		Logger log = Logger.getLogger(Chapter3Main.class);
		SqlSession sqlSession = null;
		try {
			sqlSession = SqlSessionFactoryUtils.openSqlSession();
			RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
			Role role = roleMapper.getRole(1L);
			log.info(role.getRoleName());
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}
	
	//ע��SQL����
	private static void testRoleMapper2() {
		Logger log = Logger.getLogger(Chapter3Main.class);
		SqlSession sqlSession = null;
		try {
			sqlSession = SqlSessionFactoryUtils.openSqlSession();
			RoleMapper2 roleMapper2 = sqlSession.getMapper(RoleMapper2.class);
			Role role = roleMapper2.getRole(1L);
			log.info(role.getRoleName());
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}
	
}
           

通过 SqlSession 获取了一个 RoleMapper 接口对象,然后通过getRole 方法获取对象,最后正确关闭 SqlSession 对象。

通过 logj4.properties 文件配置,让 MyBatis 打印 了其运行过程的轨迹。

log4j文件如下:

log4j.rootLogger=DEBUG , stdout
log4j.logger.org.mybatis=DEBUG
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