MyBatis一览

本文详细介绍了MyBatis框架的基本概念、核心组件及其工作原理。包括如何使用MyBatis进行数据库操作,解决传统JDBC存在的问题,以及MyBatis与Hibernate的区别。同时,还讲解了MyBatis的高级特性如动态SQL、结果映射、缓存机制等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传统jdbc操作数据库的问题
1、数据库连接,使用时创建,不使用立即释放,对数据库进行频繁的开启和关闭,造成数据库资源浪费,性能数据库性能
解决思路:使用数据库连接池管理数据库连接

2、将sql语句硬编码到java代码中,如果sql改变,需要重新编译java代码,不利于系统维护
解决思路:将sql语句配置在xml配置文件中

3、向PreapredStatement中设置参数,对占位符号位置和设置参数值,硬编码在java中
解决思路:将sql语句及占位符和参数配置在xml中

4、从resultSet遍历结果集数据,存在硬编码,获取表的字段进行硬编码,不利于维护
解决思路:将查询的结果集,自动映射到java对象

什么是mybatis:
持久层框架,apache的顶级项目-->托管到goolecode--->github
mybatis让程序员精力放到sql上。
mybatis可以向preparedStatement中的输入参数自动进行输入映射,对查询结果集灵活映射成java对象(输出映射

①sqlMapConfig.xml(mybatis的全局配置文件),配置了数据源,事务等mybatis运行环境,这些一旦和spring整合,
数据源将由第三方管理(比如c3p0),事务由spring管理。
配置映射文件mapper.xml
SqlSessionFactory(会话工厂),根据配置文件创建工厂
SqlSession(会话)---接口,面向用户的接口,用来操作数据库
④Executor(执行器),是一个接口(基本执行器,缓存执行器)
作用:sqlSession内部通过执行器操作数据库
Mapped Statement(底层封装对象)
作用:对数据库存储封装,包括sql,输入参数,输出结果类型

⑥mysql


mybatis和hibernate区别和应用场景
hibernate:
1、标准ORM框架,门槛高,不需要写sql,sql自动生成,优化sql比较困难
2、使用于需求变化不多的中小型项目,比如:后台管理系统erp.orm,oa

mybatis: 
1、专注sql本身,mybatis是一个不完全的ORM框架,虽然程序员自己写sql,但是mybatis也可以实现映射(输入映射,输出映射)
2、适用于需求变化较多的项目,比如:互联网项目


SqlSessionFactory和SqlSession:
通过SqlSessionFactory创建sqlSession,使用单例模式管理SqlSessionFactory(工厂一旦创建,使用一个实例)
SqlSession是一个面向用户的接口,提供了很多操作数据库的方法


SqlSession 是线程不安全的,在SqlSession实现类除了有接口中的方法(操作数据库的方法)还有数据域属性
SqlSession 最佳应用场合在方法体内(因为即使是单例,不同线程对于同一个方法也会有不同的内存区域,这样
sqlSession中的数据域属性就不会产生冲突,妈妈再也不用担心我是线程不安全的),定义成局部变量使用

注意:这决定了SqlSession不能为单例,因为有数据域对象,当多线程访问时,单例只有一个对象,那么数据域将
产生冲突,struts2的action是多例,因为action中可以定义成员变量,为了多线程访问时,这些成员变量不混淆,
action必须是多例的。

多个线程访问一个单例(只存在一个对象),不同线程对于同一个方法都会有不同的内存区域,所以数据不会冲突


MyBatis语法:

#{} 和 ${} 的用法
#{}表示一个占位符 ,传统写法:select * from user where id = ? 
占位符就是? 
#{}接收输入参数,类型可以是简单类型,pojo,hashmap
#{}接收pojo对象值,是通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取
#{}接收简单类型,#{}中可以写value或其他名称


${}表示一个拼接符号 ,会引起sql注入,所以不建议使用
${}接收输入参数,类型可以是简单类型,pojo,hashmap
${}接收pojo对象值,是通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取
${}接收简单类型,#{}中只能写value


添加时返回主键:

<insert id="insert" parameterType="cn.itcast.pojo.User">
	<!--    last_insert_id,uuid都为mysql函数,所以如果是oracle,就不是这种写法了
		last_insert_id:得到insert进去记录的主键值,只适用于自增主键
		keyProperty:将查询到的主键值返回到parameterType指定对象的哪个字段
		order:selectKey的执行顺序,是在insert之前还是之后执行
	-->
	<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
		SELECT LAST_INSERT_ID()
	</selectKey>

	<!--主键生成策略是uuid,的先select uuid(); 再将值保存-->
	<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
		SELECT uuid()
	</selectKey>

	insert into(id,username,birthday,sex.address) value(#{id},#{username},#{birthday},#{sex},#{address})
</insert>

测试案例

public void findUserById() throws Exception{
	//mybatis映射文件
	String resource = "SqlMapConfig.xml";
	//得到配置文件流,mybatis提供
	InputStream inputStream = Resources.getResourceAsStream(resource);
	//创建会话工厂
	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	//创建会话
	SqlSession session = sqlSessionFactory.openSession();

	//第一个参数:映射文件中statement的id=  namespace的名字+"."+statement的id
	//第二个参数:parameterType类型的参数
	User user = session.selectOne("test.findUserById",1);

	//得到列表的写法,模糊查询
	//这样写一个坏处,就是值得左右还要加%号,解决方法:${value},见mybatis语法
	//select * from user where username like '%${value}%'
	List<User> list = session.selectList("test.findUserByName","%小明%");
	
	//如果是增删改,还要提交事务
	session.commit();
	//释放资源,没有优化,应该放到finally
	session.close();
}

传统dao开发方式(Ibatis也适用):

程序需要编写dao接口和dao实现类,

需要向dao实现类中注入SqlSessionFactory,在方法体中通过SqlSessionFactory创建SqlSession

dao:定义接口方法
daoImpl:实现接口

<!--mapper配置文件:User.xml-->
<mapper namespace="test">
	<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
		select * from user where id = #{id}
	</select>
</mapper>
<!--namespace的作用和java中package,c++的namespace一样,mapper有很多个,里面可能有mapper的id相同的,
所以命名空间的作用就是对他们进行分类化,隔离-->
<!--id:底层将会把sql封装到mappedStatement对象中,所以id称为statement的id-->
在SqlMapConfig.xml中加载User.xml:
<mappers>
	<mapper resource="sqlmap/User.xml"/>
</mappers>
dao实现类:
public class UserDaoImpl implements UserDao{
	private SqlSessionFactory sqlSesssionFactory;
	//注入SqlSessionFactory
	//通过构造方法来注入,跟spring整合将由spring注入进来
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory){
		this.sqlSesssionFactory = sqlSesssionFactory;
	}

	@Override
	public void insert(User user) throws Exception{
		//线程不安全,千万不能把这个也定义为成员变量
		SqlSession sqlSession = sqlSessionFactory.openSession();
		sqlSession.insert("test.insert",user);
		//提交事务
		sqlSession.commit();
		//释放资源
		sqlSession.close();
	}
}
缺点:
(1)dao实现类,存在大量重复代码,创建sqlSession,提交事务,关闭sqlSession等
(2)sqlSession.insert("test.insert",user);  这句话,statement的id硬编码了
(3)sqlSession.insert("test.insert",user);参数为泛型,编译阶段不能发现出现,一定要运行才能发现

mybatis的mapper代理方法(相当于dao接口)代理开发方法
(1)定义mapper接口(相当于dao)
(2)编写mapper.xml
相当于比传统方法少了一个步骤,就是dao实现类daoImpl的编写

程序员编写mapper接口需要遵循一些开发规范,mybatis就可以自动生成mapper接口实现类代理对象
开发规范
a、在mapper.xml中namespace等于mapper接口地址
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
我们之前写的是test

b、mapper.java接口的方法名和mapper.xml中statement的id一致

c、mapper.java接口中方法的参数和mapper.xml中的parameterType指定的类型一致

d、mapper.java接口中的返回值和mapper.xml中的resultType指定的类型一致

总结:传统方法实现类都是重复的代码:唯一不同的是sqlSession.insert("test.insert",user);
而对于这个不同,只要遵循了abcd开发规范,就可以得出该执行什么方法,比如:
①对于test.insert(传统dao的配置,见上面代码),因为namespace改成了mapper.java的路径,那么在mapper.java中通过反射就可以得到这个路径
②对于该执行insert,还是update,还是select,通过<insert>标签,<update>标签就可以区分
③对于该执行selectOne,还是selectList,通过mapper接口的返回值就可以区分是单个pojo,还是List<Pojo>
因为:mapper代理方法就是对传统方法进行了封装

SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper("userMapper");
User user = userMapper.findUserById(1);

注意:持久层方法的参数可以使用包装类型,比如map,但是service方法不建议使用包装类型
(不利于业务层扩展,谁也不知道可map里面key是什么)


SqlMapperConfig配置文件详解:
SqlMapperConfig.xml
目前没和spring整合,数据源、事务等用写在sqlMapperConfig.xml,用的数据源也是mybatis提供的
我们在配置文件中引入数据库配置

<!--加载属性文件-->
<properties resource="db.properties">
	<!--可以定义propperty属性,但是最好别这样定义:
		他优先级会用这里定义的属性,再读取db.properties的属性,如果key一样,用property的属性值-->
</properties>
把数据库的配置单独引入出去有个好处,就是万一以后要配置集群,修改数据库配置会比较简单
操作db.properties即可
注意: 定义properties里面的key,最好有特殊性:比如
jdbc.driveClass=com.mysql.jdbc.JdbcDriver
jdbc.url = xxxxx

Mybatis别名定义(又减轻了工作量):
<!--别名定义-->
<typeAliases>
	<!--单个自定义pojo,别名定义-->
	<typeAlias type="cn.itcast.mybatis.po.User" alias="user"/>

	<!--批量别名定义:
	指定包名,mybatis自动扫描包中的po类,自定义别名,别名就是类名(首字母大小或者小写都可以)
	如果多个包,可以多个package标签
	-->
	<package name="cn.itcast.mybatis.po"/>
</typeAliases>
<!--这样在mapper中就可以直接用parameterType="user" -->

mybatis官方提供的映射类型表:



typeHandlers(类型处理器)
mybatis中通过typeHandlers完成jdbc类型和java类型的转换
通常情况下, mybatis提供的类型处理器满足日常需要,不需要自定义


<mappers>
	<!--单个文件加载,采用类路径-->
	<mapper resource="sqlmap/UserMapper.xml" />
	<!--单个文件加载,采用绝对路径-->
	<mapper resource="c:\..\.."/>

	<!--通过mapper接口加载映射文件:注意:是mapper代理方法,不是传统方法
	    需要将mapper接口类和mapper.xml映射文件名称保持一致,且在一个目录中
	-->
	<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>
	<!--批量加载,后台管理系统采用的是这种(推荐使用)-->
	<package name="cn.itcast.mybatis.mapper"/>
</mappers>


编程思想:
vo:  视图层的对象
po:  持久层的对象
pojo: 自定义对象,类似vo,po综合体


定义User的扩展类型

public class UserCustom extends User
关于用户查询的包装类型:
public class UserQueryVo{
	//用户查询条件
	private UserCustom userCustom;

	//其他查询条件
	//set get方法
}
//用户的综合查询
public List<UserCustom> findUserList<UserQueryVo userQueryVo) throws Exception;
<!--parameterType可以写别名-->
<select id="findUserList" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="cn.itcast.mybatis.po.UserCustom>
	<!--参数为自定义的pojo,#{}写的值为pojo中的属性名,
	如果pojo中是一个对象,那么就属性.属性....  ognl表达式-->
	select * from user where user.sex=#{userCustom.sex}
</select>

输入映射,输出映射:
输入映射:

parameterType:类型可以是简单类型(直接用),pojo(属性.属性....  ognl表达式),hashmap(key)
关于hashmap,#{} 里面写的是hashmap的key

输出映射:
resultType

作用:将查询结果按照sql列名 pojo属性名一致性映射到pojo中
使用resultType进行输出映射,只有查询出来的列名和pojo中的是属性名一致,该列才能映射成功
测试:可以将sql语句查询的字段取一个别名,这样讲映射不成功
a、如果查询出来的列名和pojo的属性名全部不一致,将不会创建pojo对象
b、只要查询出来的列名和pojo的属性有一个一致,将会创建pojo对象

关于输出的是一个pojo,还是一个pojo集合,resultType的配置一样,不同的是mapper接口一个返回的是
pojo类型,一个返回的是pojo集合List<Pojo>


使用resultType无法将查询结果映射到pojo对象的pojo属性中。

resultMap
应用场景:高级输出结果映射
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名
之间的映射关系。

<resultMap type="user" id="userResultMap">
	<id column="id_" property="id"/>
	<result column="username_" property ="username"/>
</resultMap>
<!--user为别名,id_为sql语句故意定义的字段别名,property定义的是user的属性名,表示column和property的对应关系-->
如果resultMap在其他的mapper中,那么要加上那个mapper的namespace

使用association和collection完成一对一和一对多的高级映射。
使用resultMap是针对那些对查询结果映射有特殊要求的功能,比如特殊要求:映射中list中包含多个list

class ResultData{
	private pojo属性    //一定要用resultMap的Association
 	private List<Pojo>属性  //一定要用resultMap的collection集合
}
resultType和resultMap比较:
resultType : 使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
如果没有查询结果的特殊要求建议用resultType


resultMap: 需要单独定义resultMap.实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射
pojo的属性中


resultMap可以实现延迟加载,association,collection具有延迟加载功能,而resultType不可以

动态sql
<where>标签
where标签可以自动去掉条件中的第一个and

<where>
	<if test="userCustom!=null">
		<if test="userCustom.sex!=null and userCustom.sex!=''">
			and user.sex=#{userCustom.sex}
		</if>
	</if>
	............
</where>

sql片段
单两个sql语句中,很多重用的条件,比如分页查询,条件一样,一个查询所有字段,一个查询count(*)
就可以把条件抽离出去,于是有了sql片段
<!--定义sql片段
经验:1、最好基于单表来定义sql片段,这样这个sql片段的可重用性才高
2、在sql片段中不要加where标签,因为我们可能在一个where标签中引用多个sql片段
-->
<sql id="query_user_where">
	<if test="userCustom!=null">
		<if test="userCustom.sex!=null and userCustom.sex!=''">
			and user.sex=#{userCustom.sex}
		</if>
	</if>
	............
</sql>

<where>
	<!--如果应用的sql片段不在本mapper中,需要加上namespace-->
	<include refid="query_user_where"></include>
	<!--可能还要引入其他sql片段-->
</where>
foreach标签:
向sql中传递数组或list,mybatis使用foreach解析
List<Integer> ids; //放在UserQueryVo中
<!--使用foreach遍历传入的ids
    实现下面拼接 AND (id= 1 or id=10 or id= 16)
-->
<foreach collection="ids" item="user_id" open="AND (" close=")" seperator="or">
	id = #{user_id}
</foreach>

<!--使用foreach遍历传入的ids
    实现下面拼接 AND id in(1,10,16)
-->
<foreach collection="ids" item="user_id" open="AND id in(" close=")" seperator=",">
	#{user_id}
</foreach>

一对多
note:上次通过反馈,查反馈记录等,竟然没成功
<!--订单及订单明细resultMap,使用extends继承,本mapper中表的字段就不用写对应关系了-->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersAndDetailResultMap extends="OrdersMap">
	<!--用于关联查询用户的信息-->
	<association property="user" javaType="cn.itcast.mybatis.po.User">
		<!--column:sql中字段的别名  property:对应User中的哪个属性-->
		<id column="user_id" property="id"/>
		<result column="username" property="username"/>
	</association>
	
	<!--一个订单,多个明细,所以是一个集合
		property:指定映射到Orders那个属性
		ofTyppe:指定多条记录的类型
	<collection property="orderdetails" ofType="cn.itcast.mybatis.po.OrderDetail">
		<id column="orderdetail_id" property="id"/>
		<result column="item_id property="itemId"/>
	</collection>
</resultMap>

sql语句:
select 
	orders.*,
	user.id user_id,
	user.username,
	user.sex,
	orderdetail.id orderdetail_id,   ##定义别名,不然id和orders的id重合了
	orderdetail.item_id,
from 
	orders orders,
	user user,
	orderdetail orderdetail
where order.user_id = user.id and orderdetail.order_id = orders.id
public class Orders{
	private ....;
	private User user;
	Private List<OrderDetail> orderdetails;
}

小结:
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中
使用resultType实现(相当于把所有字段都放在Orders中);
将订单明细映射到Orders中的orderdetails中,需要自己双重循坏遍历,去掉重复数据,
把订单放orderdetails中。

多对多
需求:查询(user)用户购买的商品(item)---多对多(一个用户对应多个商品,一个商品对应多个用户)
映射思路:
1、在user类中添加订单列表属性List<Orders> orderslist; (一对多)
2、在Orders中添加订单详情属性List<OrderDetail> orderdetails。(一对多)
3、再OrderDetail中添加items属性(一对一)
--sql:
select 
	orders.*,
	user.username,
	user.sex,
	orderdetail.id orderdetail_id,
	orderdetail.item_id,
	orderdetail.items_num,
	items.id item_id,
	items.name item_name,
from 
	orders,
	user,
	orderdetail,
	items
where orders.user_id = user.id and orderdetail.order_id=orders.id and orderdetail.item_id = items.id;
定义resultMap:
<resultMap type="xx.xx.xxx.xx.User" id="xxxx">
	<!--用户信息-->
	<id column="user_id" property="id"/>
	<result column="username" property="username"/>

	<!--订单信息,一个用户对应多个订单-->
	<collection property="orderslist" ofType="xx.xx.xx.xx.Orders">
		<id column="id" property="id"/>
		<result column="user_id" property="userId"/>
			
		<!--订单明细,一个订单对应多个明细-->
		<collection property="orderdetails" ofType="xx.xx.xxx.xxx.OrderDetail">
			<id column="orderdetail_id property="id"/>
			<result column="items_id" property="itemsId"/>
			<result column="items_num" property="itemsNum"/>

			<!--一个订单明细对应一个商品-->
			<association property="items" javaType="xxx.xx.xxx.xx.Items">
				<id column=“items_id" property="id"/>
				<result column="items_name" property="itemsName"/>
			</association>
		</collection>
	</collection>
</resultMap>
看起来挺复杂,这是多对多,一层套一层的做法,但是实际上,很少会一次性全部查出来,
一般操作,比如根据用户id查询出订单集合,如果想看详情,再根据订单id查询订单明细集合


延迟加载
先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度快。
需求:查询订单且关联查询用户信息,可以先只查询订单表即可,如果要用到用户信息,再到User表查询用户信息。

打开延迟加载开关(在sqlMapConfig.xml配置):

<setting>
	<!--全局设置懒加载,打开懒加载的开关:默认为false-->
	<setting name="lazyLoadingEnabled" value="true"/>
	<!--讲积极加载改成消极加载,即按需加载。默认为积极加载,要改成false-->
	<setting name="aggressiveLazyLoading" value="false"/>
</setting>
使用association实现延迟加载
<!--延迟加载的resultMap-->
<resultMap type="xx.xx.xx.xx.Orders" id="loadingResultMap">
	<!--对订单信息进行映射配置-->
	<id column="id" property="id"/>
	<result column="user_id" property="userId"/>
	<result column="number" property="number"/>

	<!--select表示用到的时候调用哪个方法,column:关联用户信息的列-->
	<association property="user" javaType="xx.xx.xx.User" select="xx.xx.xx.UserMapper.findUserById" column="user_id">
		<!-- 实现对用户进行延迟加载-->
	</association>
</resultMap>


<select id = "findOrderUserLazyLoading" resultMap="loadingResultMap"/>
	select * from orders
</select>

<select id="findUserById" parameterType="int" resultType="user">
	select * from User where id =#{value}
</select>

查询缓存
mybatis提供查询缓存,用于减轻数据库压力,提供数据库性能。
mybatis提供一级缓存和二级缓存
一级缓存是sqlSession级别的缓存,在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(hashmap)
用于缓存数据,不同的sqlSession之间的缓存数据区域(hashmap)是互不影响的
因为sqlSession中有成员变量,因而sqlSession是线程不安全的,写在方法中,每个线程调用这个方法,都会开启一个
内存空间,方法结束的时候,要关闭sqlSession

二级缓存是mapper级别的,多个sqlSession去操作同一个Mapper的sql语句,多个sqlSession可以共用二级缓存,
所以二级缓存是跨sqlSession的

1、一级缓存
第一次查询,没有-->查数据库,放入hashmap,有-->直接对象
如果sqlSession执行commit方法(执行插入,修改,删除),会清空SqlSession中的一级缓存,这样做的目的
是为了获取最新的数据,防止脏读


正式开发:mybatis和spring整合,事务控制在service层,一个service方法中包括多个mapper方法的调用。

service{
	/**
	* 方法开始执行时(spring会利用aop配置增强--事务管理)
	* 开启事务,创建sqlSession对象
	* /
	//第一次调用mapper的findUserById(1);   //从数据库拿

	//第二次调用mapper的findUserById(1);  //从一级缓存中查(而不是像写测试方法一样,用完sqlsession就关闭,sqlSession.close()

	/**
	*方法结束,sqlSession关闭(交给spring管理了,aop操作,方法结束了才关闭sqlSession
	*所以不用自己手动关闭sqlSession)
	*/
}

2、二级缓存:
结构:hashmap,比一级缓存更大,mapper级别的(每个namespace划分一个二级缓存区域)
多个sqlSession可以共享一个UserMapper的二级缓存区域。

执行commit提交,会清空二级缓存。(致命缺陷)
<!--开启二级缓存;在sqlMapConfig.xml中添加配置,默认值为true-->
<setting name="cacheEnabled" value="true" />

<!--在具体的mapper中,开启mapper的namespace下的二级缓存-->
<!--只这样写,会默认用mybatis默认实现的缓存,
	如果是服务器集群,配置多个机器,那么用默认的缓存实现方案是不行的,那么要实现分布式,就必须用别的产品实现,比如redis,ehcache,然后指定type-->
<cache />
开启了二级缓存,Pojo类需要实现序列化接口:
implements Serializable

为了缓存数据取出执行反序列化操作,因为二级缓存存储介质多样, 不一定在内存,也可以是硬盘,或者网络。


在mapper.xml中配置了<cache/>,那么查询方法就都有了二级缓存,如果想要禁用,那么在单独的sql中添加一个配置:
禁用二级缓存
<select id="xxx" resultMap="xxx" useCache="false"/>


刷新缓存(清除缓存):
在mapper的同一个namespace下,如果有insert,update,delete 操作数据后都会执行刷新缓存,如果不执行,会出现脏读
<!--默认为true,如果改成false,则不刷新缓存,会产生一个严重后果就是,会出现脏读-->
<insert id="xxx" parameterType="xxx" flushCache="true"/> 

二级缓存整合其他分布式缓存框架(应该场景不多,所以一般不配置)
mybatis默认提供的缓存方案,不支持分布式缓存,要想进行分布式缓存,就必须用其他的分布式缓存框架进行整合

思路:
mybatis提供了一个cache接口,如果实现自己的缓存逻辑,实现cache接口开发即可
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现

下面整合ehcache:
ehcache-core-2.6.5.jar
mybatis-ehcache-1.0.2.jar

那么mapper.xml中的配置:
<!--type指定Cache接口的实现类,如果不填就会用mybatis默认提供的实现类PerpetualCache-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

mybatis默认实现的cache类是: 
public class PerpetualCache implements Cache{
	private String id;
	private Map<Object,Object> cache = new HashMap<Object,Object>();
}
二级缓存的局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好
--因为它只要commit,就会清除所有的缓存,无法做到,只刷新commit的那个pojo,因此,缓存命中率不同,所以要对业务需求做针对性的缓存

应用场景
对于 访问多的查询请求且用户对查询结果实时性要求不高,可以采用mybatis的二级缓存降低数据库访问量
--比如耗时高的统计分析sql,账单查询等

逆向工程:
数据库的表生成java代码
mybatis官方提供逆向工程:mybatis-generator-core-1.3.2-bundle.zip
里面有官方文档,有具体的使用方法,简明清晰
提供几种生成方法:
1、命令行
2、ant
3、maven
4、java program with xml configuration (常用,文档中有配置案例)
5、java program with java based configuration
6、eclipse plugin

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值