MyBatis一览

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值