mybatis必知必会

1、SqlSessionFactory

2、SqlSession

3、Mapper XML 文件

4、动态SQL

5、常用API

6、集成spring

6.1、SqlSessionFactoryBean

6.2、SqlSessionTemplate

 

前沿:什么是mybatis,为什么需要她?

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。

MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

优点:比原生jdbc简单,少写很多通用的代码。比类似hibernate简单,直观,可操作性强。

 -------------------------------------------------------------------------------------------------------------------------

1、SqlSessionFactory

要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于 classpath 中即可。

ps:如果使用 Maven 来构建项目,则需将下面的 dependency 代码置于 pom.xml 文件中,相应version可以在http://www.mvnrepository.com/ maven中央库去查找,或者自己的私服。

 

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

 

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。其实就是session管理的一个工厂。

SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得,而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

 

public SqlSessionFactory SqlSessionFactory(){
		DataSource dataSource ;//数据库连接池,使用第三方即可
		TransactionFactory transactionFactory = new JdbcTransactionFactory();//事物,使用默认。也可以配合spring,使用spring自带的
		Environment environment = new Environment("development", transactionFactory, dataSource);//环境配置即 开发或者生产
		
		Configuration configuration = new Configuration(environment);//配置中心
		//configuration.addMappers("conge.wang.sqlmappers");//加载mappers xml package,及扫描conge.wang.sqlmappers下面的xml配置
		//configuration.addMapper(TestSqlMapper.class);//或者加载mappers class。不过不推荐使用
		
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);//从SqlSessionFactoryBuilder构建
		
		return sqlSessionFactory;
	}
 注意点:

 

(1)、SqlSessionFactoryBuilder 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳范围是方法范围(也就是局部方法变量)。你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情。

 

(2)、SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此 SqlSessionFactory 的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

 

 

2、SqlSession

SqlSession  可以理解为一个jdbc Connection。

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的范围是请求或方法范围。

绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。

也绝不能将 SqlSession 实例的引用放在任何类型的管理范围中,比如 Serlvet 架构中的 HttpSession。

那么也就是说,每次操作时,获取新的SqlSession,并且确保完成数据库操作之后,确保关闭,例如:

 

SqlSession session = sqlSessionFactory.openSession();
try {
  // 业务处理
} finally {
  session.close();
}

 

注意点:

(1)、一定确保SqlSession是线程安全使用

(2)、一定确保使用完成,或者异常时,关闭SqlSession

 

 

3、Mapper XML 文件

MyBatis的核心就在Mapper XML文件的配置,大显身手的地方。

SQL 映射文件有很少的几个顶级元素,

 

resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。

sql – 可被其他语句引用的可重用语句块。

insert – 映射插入语句

update – 映射更新语句

delete – 映射删除语句

select – 映射查询语句

(0)、先建张表,以备使用,mysql数据库

CREATE TABLE `t_test` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(50) NOT NULL DEFAULT '0',
	`num` INT(11) NOT NULL DEFAULT '0',
	`create_ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;

 
定义下面的这些的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="t_test">

...//SQL语句配置
</mapper >
 

(1)、即预定义一些SQL语句,其他SQL配置可以直接引用,省去很多重复编码

<sql id="baseResult">
     id,name,num,create_ts
</sql>

上面定义了t_test 表的所有字段 ,也可以定义一些复杂的通用的SQL代码,但最好一目了然,太复杂不利于维护,二次开发。这也正是魅力所在。

(2)、resultMap ,定义SQL表字段对java pojo的映射,可以理解为ORM,对象--表对应

<resultMap id="baseMap" type="pojo.TTest">
	<id column="id"              property="id" />
	<result column="name" 	     property="name" />
	<result column="balance"     property="num" />
	<result column="create_ts"   property="createTs" />
</resultMap>

虽然映射了表和POJO的对象,但是不一定全部字段映射,也不一定非要每个表都要映射,也可以多个表的join之后的字段映射为一个POJO,总之一句话,灵活使用。 

(3)、select ,查询语句。

<select id="query" parameterType="map" resultMap="baseMap">
	SELECT <include refid="baseResult"/>
		FROM t_test
        WHERE id = #{id}
</select>
 注意点:

a)、id 在命名空间中唯一的标识符,可以被用来引用这条语句。

b)、parameterType 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。

         其实做为parameterType 无非三类参数,1.直接一个基本类型的数据 2.一个java bean的参数,包含多个基本类型 3、map类型

c)、resultMap  外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用。

d)、resultType  java类,包含多个基本类型 ,和resultMap作用一样,用来映射结果集 

 其他的还有一些属性,用的时候在查即可。

 

#{id} 即接收一个id的参数,就像PreparedStatement 预处理SQL语句,占位符。

 

(4)insert, update 和 delete 基本类似

insert语句,selectKey使用Mysql自带的主键自增长特性 

 

<insert id="insert" parameterType="pojo.TTest">
  insert into t_test(id,name,num)
  values (#{id},#{name},#{num})

        <selectKey keyProperty="id" resultType="java.lang.Long">
		  SELECT LAST_INSERT_ID() AS ID
	</selectKey>
</insert>
 update语句
<update id="update" parameterType="map">
	UPDATE t_test
		SET num = #{num}
	WHERE id = #{id}
</update>
 删除语句
<delete id="delById" parameterType="long">
	DELETE FROM t_test
		WHERE id = #{id}
</delete>
 

 平时使用MyBatis开发时,和这些配置则是打交道最频繁的,所以写SQL的时候,一定要规范好。

 

 

4、动态SQL

MyBatis强大的另外一个地方则是动态SQL。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。

(1)、if

动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。例如:

<select id="query" parameterType="map" resultMap="baseMap">
	SELECT <include refid="baseResult"/>
		FROM t_test
	WHERE 1=1
	  <if test="id!=0">
               AND id = #{id}
          </if>   
</select>

 还是基于上个SELECT语句,只不过加了一句动态的条件附加语句。这个时候,如果id!=0,会执行AND id = #{id},如果id==0,则不会执行这一句。

动态体现的淋漓尽致。

(2)、choose, when, otherwise

有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

<select id="query" resultType="Blog">
	SELECT <include refid="baseResult"/>
		FROM t_test
	WHERE 1=1
	  <choose>
		<when test="flag == 1">
		  AND id> #{id}
		</when>
		<when test="flag == 2">
		  AND id= #{id}
		</when>
		<otherwise>
		  AND #{id} > id 
		</otherwise>
	  </choose>
</select>
 这个时候使用flag字段不同值,对应的SQL语句不同

(3)、foreach  非常有用的一个语法

动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

<select id="query" parameterType="map" resultMap="baseMap">
	SELECT <include refid="baseResult"/>
		FROM t_test
	WHERE ID in
	  <foreach collection="idList" item="item" index="index"  open="(" separator="," close=")">
			#{item}
	  </foreach>
</select>
 如果查询一组id,可以使用foreach

ps:关于exist于in 的使用,如果id数组范围小,使用in,如果id数组范围大于查询的表的本身,使用exist。一句话,从少的结果集中扫描。

(4)、like,不是MyBatis的特性,只是偶尔用下。不要乱用,性能不行。

select * from my_tab  
where keywords like CONCAT('%',#{keywords},'%' )  

5、常用API

SqlSessionFactory 很少操作,不必刻意记住一下api,需要时查询即可。但是SqlSession有一些使用频率非常高的api,在使用的过程,不刻意记,也记住了。

这些方法被用来执行定义在 SQL 映射的 XML 文件中的 SELECT,INSERT,UPDA E T 和 DELETE 语句。它们都会自行解释,每一句都使用语句的 ID 属性和参数对象,参数可以 是原生类型(自动装箱或包装类) ,JavaBean,POJO 或 Map。

<T> T selectOne(String statement, Object parameter)//只返回一条数据,如果有多条结果时,会报错,建议此类的select 语句最后加一句limit 1
<E> List<E> selectList(String statement, Object parameter)//返回多条数据
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)//插入
int update(String statement, Object parameter)//更新
int delete(String statement, Object parameter)//删除
至于使用映射器,就罢了,不用也没啥。 

6、集成spring

6.1、SqlSessionFactoryBean

6.2、SqlSessionTemplate

要使用 MyBatis-Spring 模块,你只需要包含 mybatis-spring-x.x.x.jar 文 件就可以了,并在类路径中加入相关的依赖。相应version可以在http://www.mvnrepository.com/ maven中央库去查找,或者自己的私服。

如果你使用 Maven,那么在 pom.xml 中加入下面的代码即可:

 

dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>x.x.x</version>
</dependency>
 这个时候,SqlSessionFactory,SqlSession就交给了spring管理。spring使用SqlSessionFactoryBean去代理SqlSessionFactory,使用SqlSessionTemplate去代理SqlSession。
import java.beans.PropertyVetoException;
import java.io.IOException;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.support.TransactionTemplate;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
public class DbConfig {
	
	@Bean 
	public DataSource DataSource() throws PropertyVetoException{
		DruidDataSource ds = new DruidDataSource();
		
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl(XX);
		ds.setUsername(XX);
		ds.setPassword(XX);
		
                //配置数据库连接池
		return ds;
	}
	
	@Bean
	public SqlSessionFactoryBean SqlSessionFactoryBean() throws IOException, PropertyVetoException {
		SqlSessionFactoryBean fc = new SqlSessionFactoryBean();
		fc.setDataSource(DataSource());
		
		ResourcePatternResolver resoler = ResourcePatternUtils.getResourcePatternResolver(new DefaultResourceLoader());
		
		fc.setMapperLocations(resoler.getResources("sql/*/*.xml"));//扫描sql包下面的子包下面的mapper xml文件
		
		return fc;
	}
	
	@Bean
	public SqlSessionTemplate SqlSessionTemplate() throws Exception {
		SqlSessionTemplate sqlSession = new SqlSessionTemplate(SqlSessionFactoryBean().getObject());
		
                //SqlSessionTemplate 是线程安全的,放心使用
		return sqlSession;
	}
	
	@Bean
	public DataSourceTransactionManager transactionManager() throws PropertyVetoException{
		DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
		transactionManager.setDataSource(DataSource());
		
		return transactionManager;
	}
	
	@Bean
	public TransactionTemplate TransactionTemplate() throws PropertyVetoException{
		TransactionTemplate tsTemplate = new TransactionTemplate();
		tsTemplate.setTransactionManager(transactionManager());
		tsTemplate.setIsolationLevel(Isolation.DEFAULT.value());//事物级别采用数据库默认
		tsTemplate.setPropagationBehavior(Propagation.REQUIRED.value());//事物传播行为采用默认
		
		return tsTemplate;
	}
	
}
   注意点:
 这个时候,SqlSessionFactory,SqlSession就交给了spring管理。spring使用SqlSessionFactoryBean去代理SqlSessionFactory,使用SqlSessionTemplate去代理SqlSession。
import java.beans.PropertyVetoException;
import java.io.IOException;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.support.TransactionTemplate;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
public class DbConfig {
	
	@Bean 
	public DataSource DataSource() throws PropertyVetoException{
		DruidDataSource ds = new DruidDataSource();
		
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl(XX);
		ds.setUsername(XX);
		ds.setPassword(XX);
		
                //配置数据库连接池
		return ds;
	}
	
	@Bean
	public SqlSessionFactoryBean SqlSessionFactoryBean() throws IOException, PropertyVetoException {
		SqlSessionFactoryBean fc = new SqlSessionFactoryBean();
		fc.setDataSource(DataSource());
		
		ResourcePatternResolver resoler = ResourcePatternUtils.getResourcePatternResolver(new DefaultResourceLoader());
		
		fc.setMapperLocations(resoler.getResources("sql/*/*.xml"));//扫描sql包下面的子包下面的mapper xml文件
		
		return fc;
	}
	
	@Bean
	public SqlSessionTemplate SqlSessionTemplate() throws Exception {
		SqlSessionTemplate sqlSession = new SqlSessionTemplate(SqlSessionFactoryBean().getObject());
		
                //SqlSessionTemplate 是线程安全的,放心使用
		return sqlSession;
	}
	
	@Bean
	public DataSourceTransactionManager transactionManager() throws PropertyVetoException{
		DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
		transactionManager.setDataSource(DataSource());
		
		return transactionManager;
	}
	
	@Bean
	public TransactionTemplate TransactionTemplate() throws PropertyVetoException{
		TransactionTemplate tsTemplate = new TransactionTemplate();
		tsTemplate.setTransactionManager(transactionManager());
		tsTemplate.setIsolationLevel(Isolation.DEFAULT.value());//事物级别采用数据库默认
		tsTemplate.setPropagationBehavior(Propagation.REQUIRED.value());//事物传播行为采用默认
		
		return tsTemplate;
	}
	
}
   注意点:

 (1)、在基本的 MyBatis 中,session 工厂可以使用 SqlSessionFactoryBuilder 来创建。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来替代。

也可以使用xml配置,例如:

 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
</bean>
  mapperLocations配置就是扫描该包下的mapper xml配置文件

(2)、事物,就用spring的。关于事物,一两句说不完整,要单独篇幅了。

(3)、 SqlSessionTemplate 是线程安全的, 可以被多个 DAO 所共享使用。业界良心啊!所有一切有陷阱的代码都不是好代码。

 

怎么使用SqlSessionTemplate?

@Repository
public class TestRepository {
	@Autowired SqlSession session;
	
	public TTest queryById(long id){
		return session.selectOne("t_test.query", id);
	}
}

 

简洁而不简单。简于形而繁于心,这种设计真的超赞。

 

 

 

 --------------------------------------------------------------------------------------------------------------------------------

总结:MyBatis其实是一个半ORM的持久化框架,但正是这种特性,开发人员更能更加灵活的运用,订制SQL语句,直接提升性能。

如果说hibernate是一把M16,那么MyBatis就是一把AK47。

我喜欢MyBatis。

 

猜你喜欢

转载自haoran-10.iteye.com/blog/2257417