1. Mybatis介绍
市场上所用的框架
Ø Hibernate
Ø jdbcTemplate
Ø ibatis
Ø mybatis
mybatis的优点
Ø 对jdbc做了很好的封装
Ø 容易掌握
Ø 灵活性强
Mybatis的安装包
lib:第三方的依赖包
mybatis-3.1.1.jar:核心包
mybatis-3.1.1.pdf:说明文档
mybatis-3.1.1-javadoc.jar:mybatis的api
mybatis-3.1.1-source.jar:源代码
2. mybatis的第一个例子
1. 第一步创建java项目
2. 导入所需要的jar
3. 建表
4. 建立实体类
5. 创建配置文件
sqlMapConfig.xml
6. 库表的mapping映射文件
PersonMapper.xml
7. 编写测试代码
public class PersonTest {
/**
* 创建session工厂
*/
SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
String resource = "sqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/**
* 根据id查询person
* @author:
* @email:renliang@itcast.com
* @qq交流群:208879353
* @company:cn.itcast
*/
@Test
public void selectPersonById() {
//创建session
SqlSession session = sqlSessionFactory.openSession();
try {
//第一个参数namespace+"."+sql的id,第二个参数就是sql所需要的参数
Person person = session.selectOne(
"cn.itcast.model.Person.selectPersonById", 1);
System.out.println(person);
}finally {
//关闭连接
session.close();
}
}
}
3. Select 的语句的基本使用
1. List实体类的方式集合的查询
/**
* 查询person的集合
* @author:
* @email:renliang@itcast.com
* @qq交流群:208879353
* @company:cn.itcast
*/
@Test
public void selectPersonList(){
//创建session
SqlSession session = sqlSessionFactory.openSession();
try {
//第一个参数namespace+"."+sql的id,第二个参数就是sql所需要的参数
List<Person> personList = session.selectList(ns+"selectPersonList");
for(Person person : personList){
System.out.println(person);
}
}finally {
//关闭连接
session.close();
}
}
2. 以map方式返回实体
/**
* 根据id查询person返回map实体
* @author:
* @email:renliang@itcast.com
* @qq交流群:208879353
* @company:cn.itcast
*/
@Test
public void selectPersonByIdForMap(){
//创建session
SqlSession session = sqlSessionFactory.openSession();
try {
//第一个参数namespace+"."+sql的id,第二个参数就是sql所需要的参数
Map<String, Object> person = session.selectOne(
"cn.itcast.model.Person.selectPersonByIdForMap", 1);
System.out.println(person);
}finally {
//关闭连接
session.close();
}
}
3. 返回map的集合
/**
* 返回map的集合
* @author:
* @email:renliang@itcast.com
* @qq交流群:208879353
* @company:cn.itcast
*/
@Test
public void selectPersonListForMap(){
//创建session
SqlSession session = sqlSessionFactory.openSession();
try {
//第一个参数namespace+"."+sql的id,第二个参数就是sql所需要的参数
List<Map<String, Object>> personMapList = session.selectList(ns+"selectPersonListForMap");
System.out.println(personMapList);
}finally {
//关闭连接
session.close();
}
}
4. ResultMap的使用
5. resultMap和resultType的区别
6. 模糊查询
4. insert的使用
1. 基本插入
/**
* insert
* @author:
* @email:renliang@itcast.com
* @qq交流群:208879353
* @company:cn.itcast
*/
@Test
public void insert(){
//创建session
SqlSession session = sqlSessionFactory.openSession();
Person person = new Person();
person.setPersonName("张三");
person.setPersonAge(300);
person.setPersonAddress("盘丝洞");
try {
//瞬间改了mysql的数据库的隔离级别,把它变成可提交读,需要手动的提交
session.insert(ns + "insert", person);
//手动提交
session.commit();
} catch (Exception e) {
session.rollback();
}finally{
session.close();
}
}
2. 主键的返回
5. update的使用
注意:某些不设置会出现值被置空的情况
/**
* update
* @author:
* @email:renliang@itcast.com
* @qq交流群:208879353
* @company:cn.itcast
*/
@Test
public void update(){
//创建session
SqlSession session = sqlSessionFactory.openSession();
Person person = new Person();
person.setPersonId(2);
person.setPersonName("李四");
//如果某些字段不设置会出现值被置空的情况,需要使用动态sql来解决
//person.setPersonAge(100);
//person.setPersonAddress("花果山");
try {
//瞬间改了mysql的数据库的隔离级别,把它变成可提交读,需要手动的提交
session.update(ns + "update", person);
//clazz.setclassId(person.getPersonId());
//手动提交
session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}finally{
session.close();
}
}
6. delete使用
/**
* update
* @author:
* @email:renliang@itcast.com
* @qq交流群:208879353
* @company:cn.itcast
*/
@Test
public void delete(){
//创建session
SqlSession session = sqlSessionFactory.openSession();
try {
//瞬间改了mysql的数据库的隔离级别,把它变成可提交读,需要手动的提交
session.delete(ns + "delete", 2);
//手动提交
session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}finally{
session.close();
}
}
7. 别名的定义
1.
2. 定义一端sql
8. 动态sql
8.1 select动态组合条件查询
注意:1. <where>会给我们自动的处理第一个and
2.当实体类里面定义了基本的数据类型,where里面的判断空就不起作用了
8.2update动态更新
注意:1. <set>会给我们自动的处理最后一个逗号
2.当实体类里面定义了基本的数据类型,where里面的判断空就不起作用了
8.3foreach
l In查询
@Test
public void queryUserByForEachTest(){
//打开一个会话
SqlSession session = sqlSessionFactory.openSession();
try{
//Integer [] ids = {6, 7, 8};
//List ids = new ArrayList();
/*ids.add(6);
ids.add(7);
ids.add(8);*/
/*ids.add("6");
ids.add("7");
ids.add("8");*/
//更改当前代码下面的所有相同变量名Shift+Alt+R
Set ids = new HashSet();
ids.add(6);
ids.add(7);
ids.add(8);
Map<String, Object> map = new HashMap<String, Object>();
map.put("ids", ids);
List<User> uList = session.selectList("cn.itcast.User.queryUserByForEach", map);
for(User user : uList){
System.out.println(user);
}
}catch(Exception ex){
ex.printStackTrace();
session.rollback();
}finally{
session.close();
}
}
l 批量插入
<insert id="insertBatch">
<selectKey keyProperty="userId" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
insert into USER (USER_ID, USERNAME, PASSWORD, BIRTHDAY, USER_ADDR)
values
<foreach collection="uList" item="user" separator=",">
(#{user.userId},#{user.username}, #{user.password}, #{user.birthday}, #{user.userAddr})
</foreach>
</insert>
l 批量删除
<delete id="delete" parameterType="map">
delete from user where user_id in
<foreach collection="ids" open="(" close=")" item="userId" separator=",">
#{userId}
</foreach>
</delete>
9. 联合查询
1. 建表
2. 创建mapping的文件
Mybatis generator使用方法
l 安装mybatis generator插件
Help—>install from site...
l 点击add
l 输入name和location后点击ok
http://mybatis.googlecode.com/svn/sub-projects/generator/trunk/eclipse/UpdateSite/
l 创建generator的核心文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
<!-- 制定mysql的驱动包的路径 千万别放中文路径下 -->
<classPathEntry location="D:\mysql-connector-java-5.0.8-bin.jar" />
<!-- 配置数据源和生成的代码所存放的位置 -->
<context id="context1">
<commentGenerator>
<!-- 去除自动生成的注释 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/mybatis" userId="root"
password="root" />
<!-- 所生成的实体类的位置默认资源包src -->
<javaModelGenerator targetPackage="cn.itcast.model"
targetProject="mybatis-3" />
<!-- 所生成的sqlMap的影射文件的位置,默认资源包src -->
<sqlMapGenerator targetPackage="mybatis.sqlMap"
targetProject="mybatis-3" />
<!-- 为哪些表生成代码 tableName:表名 schema:不用填写,其余属性是禁用例子查询的生成 -->
<table schema="" tableName="person" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" selectByExampleQueryId="false">
</table>
</context>
</generatorConfiguration>
l 处理多余的文件
l 多对一的关联查询
l 一对多的关联映射
l 多对多关联映射即使特殊的一对多
10. 延迟加载
在做联合查询是查出首层实体对象,具体实体对象内部的关联对象只有用到的时候才去查询使用。
首先在mybatis核心配置文件中配置:
lazyLoadingEnabled:true使用延迟加载,false禁用延迟加载。默认为true
aggressiveLazyLoading:true启用时,当延迟加载开启时访问对象中一个懒对象属性时,将完全加载这个对象的所有懒对象属性。false,当延迟加载时,按需加载对象属性(即访问对象中一个懒对象属性,不会加载对象中其他的懒对象属性)。默认为true
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
10.1 一对多延迟加载
需要两条sql语句配合使用
第一步配置resultMap
Collection:是person内部的集合,
select:延迟加载的sql语句
column:延迟加载sql语句的查询条件的列名
<resultMap type="cn.itcast.model.Person" id="personLazyRM" extends="personRM">
<collection property="ordersList" column="person_id" select="mybatis.sqlMap.OrdersMapper.selectOrderByPersonId">
</collection>
</resultMap>
查询语句
<select id="selectForLazy" parameterType="int" resultMap="personLazyRM">
select * from person p where p.person_id = #{personId}
</select>
延迟加载的查询语句
<select id="selectOrderByPersonId" parameterType="int" resultMap="BaseResultMap">
select * from orders o where o.person_id = #{personId}
</select>
10.2多对一或一对一的延迟加载
ResultMap
<resultMap type="cn.itcast.model.Orders" id="lazyRM" extends="BaseResultMap">
<association property="person" column="order_id" select="cn.itcast.model.Person.selectPersonByOrderId">
</association>
</resultMap>
查询语句
<select id="selectByPrimaryKeyForLazy" resultMap="lazyRM" parameterType="java.lang.Integer" >
select * from orders where order_id = #{orderId}
</select>
延迟加载的查询语句
<select id="selectPersonByOrderId" parameterType="int" resultMap="personRM">
select p.* from person p, orders o where p.person_id = o.person_id and o.order_id = #{orderId}
</select>
11.一级缓存
12.二级缓存
一个项目中肯定会存在很多共用的查询数据,对于这一部分的数据,没必要
每一个用户访问时都去查询数据库,因此配置二级缓存将是非常必要的。
Mybatis的二级缓存配置相当容易,要开启二级缓存:
1. 在核心配置文件中加入<setting name="cacheEnabled" value="true"/>
2. 要在你的Mapper映射文件中添加一行: <cache />
3. 在select语句中useCache=false可以禁用当前的语句的二级缓存,即每次查询夸session 的查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
4.l 映射文件中所有的insert、update和delete语句将刷新缓存,三个语句中有flushCache="true" 属性,默认情况下为true,即同个sessionFactory中当有sql语句更新时缓存自动被刷新以保证数据的实时性,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读, 缓存将使用LRU(Least Recently Used)最近最少使用策略算法来回
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。可用的收回策略有, 默认的是 LRU:
1. LRU – 最近最少使用的:移除最长时间不被使用的对象。
2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。
13.二级缓存框架
采用mybatis的二级缓存框架
第一步:引入缓存的依赖包
第二步:引入缓存配置文件
ehcache.xml
defaultCache配置说明:
maxElementsInMemory 内存中最大缓存对象数.当超过最大对象数的时候,ehcache会按指定的策略去清理内存
eternal 缓存对象是否永久有效,一但设置了,timeout将不起作用.
timeToIdleSeconds 设置Element在失效前的允许闲置时间.仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大.
timeToLiveSeconds:设置Element在失效前允许存活时间.最大时间介于创建时间和失效时间之间.仅当element是永久有效时使用,默认是0.,也就是element存活时间无穷大.
overflowToDisk 配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中.
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
maxElementsOnDisk 磁盘中最大缓存对象数,若是0表示无穷大.
diskPersistent 是否在重启服务的时候清楚磁盘上的缓存数据.true不清除.
diskExpiryThreadIntervalSeconds 磁盘失效线程运行时间间隔.
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存.默认策略是LRU(最近最少使用).你可以设置为FIFO(先进先出)或是LFU(较少使用).
第三步:修改mapper文件中缓存类型
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
14基于注解的开发
使用注解的开发需要提供一个接口,即dao的接口,不需要实现类,初始化环境时要把接口注册
@Before
public void setUp() throws Exception {
String sqlMapConfig = "sqlMapConfig.xml";
//读取mybatis的核心配置文件
InputStream in = Resources.getResourceAsStream(sqlMapConfig);
//实例化会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
sqlSessionFactory.getConfiguration().addMapper(PersonDao.class);
}
1. 查询所有员工
接口方法:
@Select("select * from person1")
//@Options(useCache =true, flushCache =false, timeout =10000)
@Results(value = {
@Result(id =true, property ="personId", column ="person_id"),
@Result(property ="personName", column ="person_name"),
@Result(property ="birthday", column ="birthday"),
@Result(property ="address", column ="address"),
@Result(property ="gender", column ="gender")
})
public List<Person> queryPersonAll();
调用方法:
@Test
public void queryPersonAllTest() {
//打开会话
SqlSession session = sqlSessionFactory.openSession();
try {
PersonDao personDao = session.getMapper(PersonDao.class);
List<Person> pList = personDao.queryPersonAll();
for(Person person : pList){
System.out.println(person);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
session.close();
}
}
2. 根据id查询员工
接口方法:
@Select("select * from person1 t where t.person_id = #{personId}")
@Results(value = {
@Result(id =true, property ="personId", column ="person_id"),
@Result(property ="personName", column ="person_name"),
@Result(property ="birthday", column ="birthday"),
@Result(property ="address", column ="address"),
@Result(property ="gender", column ="gender")
})
public Person getPersonById(Integer personId);
调用方法:
@Test
public void getPersonByIdTest(){
SqlSession session = sqlSessionFactory.openSession();
try {
PersonDao personDao = session.getMapper(PersonDao.class);
Person person = personDao.getPersonById(1);
System.out.println(person);
} catch (Exception e) {
e.printStackTrace();
}finally{
session.close();
}
}
3. 根据不同条件查询
接口方法:
@Select("select * from person1 t where t.person_name like '%${personName}%' and t.gender = #{gender}")
@Results(value = {
@Result(id =true, property ="personId", column ="person_id"),
@Result(property ="personName", column ="person_name"),
@Result(property ="birthday", column ="birthday"),
@Result(property ="address", column ="address"),
@Result(property ="gender", column ="gender")})
public List<Person> getPersonByParam(Map<String, Object> map);
调用方法:
@Test
public void getPersonByParamTest(){
SqlSession session = sqlSessionFactory.openSession();
try {
PersonDao personDao = session.getMapper(PersonDao.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("personName", "赵六");
map.put("gender", "0");
List<Person> pList = personDao.getPersonByParam(map);
for(Person person : pList){
System.out.println(person);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
session.close();
}
}
4. 联合查询
注意:需要结合配置文件方式的resultMap
调用方法
@Select("select * from person1 p, orders o where p.PERSON_ID = o.PERSON_ID and p.PERSON_ID = #{personId}")
@ResultMap(value="cn.itcast.model.Person.personWithOrderRM")
public Person getPersonOne2Many(Integer personId);
配置文件中的resultMap
<resultMap type="person" id="personWithOrderRM" extends="personRM">
<collection property="orderList" ofType="cn.itcast.model.Orders">
<id column="ORDER_ID" jdbcType="INTEGER" property="orderId" />
<result column="PERSON_ID" jdbcType="INTEGER" property="personId" />
<result column="ORDER_NO" jdbcType="VARCHAR" property="orderNo" />
<result column="TOTAL_SUM" jdbcType="REAL" property="totalSum" />
<result column="ORDER_ADDR" jdbcType="VARCHAR" property="orderAddr" />
</collection>
</resultMap>
调用方法:
@Test
public void getPersonOne2ManyTest(){
SqlSession session = sqlSessionFactory.openSession();
try {
PersonDao personDao = session.getMapper(PersonDao.class);
Person person = personDao.getPersonOne2Many(1);
System.out.println(person);
} catch (Exception e) {
e.printStackTrace();
}finally{
session.close();
}
}
5. 修改
调用方法
@Update(value="update person1 t set"
+" t.person_name = #{personName} , "
+" t.birthday = #{birthday}, "
+" t.address=#{address},"
+" t.gender = #{gender}"
+" where t.person_id = #{personId}")
public void update(Person person);
调用方法:
@Test
public void updateTest() throws Exception{
//打开会话
SqlSession session = sqlSessionFactory.openSession();
try{
PersonDao personDao = session.getMapper(PersonDao.class);
Person person = new Person();
person.setPersonId(1);
person.setPersonName("李武");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = format.parse("1992-12-10");
person.setBirthday(date);
personDao.update(person);
session.commit();
}catch(Exception ex){
session.rollback();
ex.printStackTrace();
}finally{
session.close();
}
}
6. 插入
接口方法:
@Insert("insert into person1 (person_id, person_name, birthday, address, gender)values(#{personId},#{personName},#{birthday},#{address},#{gender})")
@SelectKey(keyProperty="personId", before = false, resultType = Integer.class, statement = { "select last_insert_id()" })
public void save(Person person);
调用方法:
@Test
public void insertTest() throws Exception{
//打开会话
SqlSession session = sqlSessionFactory.openSession();
try{
PersonDao personDao = session.getMapper(PersonDao.class);
Person person = new Person();
person.setPersonName("王五");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = format.parse("1990-12-10");
person.setAddress("beijing");
person.setBirthday(date);
person.setGender("0");
personDao.save(person);
session.commit();
}catch(Exception ex){
session.rollback();
ex.printStackTrace();
}finally{
session.close();
}
}
7. 动态条件组合查询
接口方法:
@SelectProvider(type=SQLHelp.class,method="getSql")
public List<Person> queryPersonByCondition(Map<String, Object> map);
获得sql的帮助类
package cn.itcast.model;
import static org.apache.ibatis.jdbc.SqlBuilder.BEGIN;
import static org.apache.ibatis.jdbc.SqlBuilder.FROM;
import static org.apache.ibatis.jdbc.SqlBuilder.SELECT;
import static org.apache.ibatis.jdbc.SqlBuilder.SQL;
import static org.apache.ibatis.jdbc.SqlBuilder.WHERE;
import java.util.Date;
import java.util.Map;
public class SQLHelp {
public String getSql(Map<String, Object> parameters) {
String personName = (String) parameters.get("personName");
Date birthday = (Date) parameters.get("birthday");
String address = (String) parameters.get("address");
String gender = (String) parameters.get("gender");
BEGIN();
SELECT("*");
FROM("person1");
if(personName != null){
WHERE("person_name = #{personName}");
}
if(birthday != null){
WHERE("birthday < #{birthday}");
}
if(address != null){
WHERE("address = #{address}");
}
if(gender != null){
WHERE("gender = #{gender}");
}
return SQL();
}
}
调用方法:
@Test
public void queryPersonByConditionTest() throws Exception{
//打开会话
SqlSession session = sqlSessionFactory.openSession();
try{
PersonDao personDao = session.getMapper(PersonDao.class);
Map<String, Object> map = new HashMap<String, Object>();
//map.put("personName", "五");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = format.parse("1990-04-01");
map.put("birthday", date);
//map.put("address", "beijing2");
map.put("gender", "0");
List<Person> personList = personDao.queryPersonByCondition(map);
for(Person person : personList){
System.out.println(person);
}
session.commit();
}catch(Exception ex){
session.rollback();
ex.printStackTrace();
}finally{
session.close();
}
}
ssm整合springmvc+spring+mybatis
1. 创建一个web工程
2. 导入所依赖的jar
<filter>
<filter-name>SpringCharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SpringCharacterEncodingFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>