PO类
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息
private User user;
。。。
}
映射文件
"cn.com.model.Orders" id="userordermap">
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
property="user" javaType="cn.com.model.User">
<id property="id" column="user_id" />
<result property="username" column="username" />
<result property="address" column="address" />
多对一中,使用association 映射一方
property="user" javaType="cn.com.model.User">
<id property="id" column="user_id" />
<result property="username" column="username" />
<result property="address" column="address" />
“id” 会使用orders中的user_id 对id进行赋值
property : 多方中对应的一方的属性名
javaType:类型
PO类
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息
private User user;
//订单明细
private List orderdetails;
。。。。
}
映射文件
"cn.com.model.Orders" id="userorderdetailmap">
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
property="user" javaType="cn.com.model.User">
<id property="id" column="user_id" />
<result property="username" column="username" />
<result property="address" column="address" />
property="orderdetails" ofType="cn.com.model.Orderdetail">
<id property="id" column="orderdetail_id" />
<result property="itemsId" column="items_id" />
<result property="itemsNum" column="items_num" />
一对多中,一方中会定义多方的一个集合,在映射文件中使用collection映射。
property="orderdetails" ofType="cn.com.model.Orderdetail">
<id property="id" column="orderdetail_id" />
<result property="itemsId" column="items_id" />
<result property="itemsNum" column="items_num" />
property:一方中的多方集合属性名称。
ofType:指定关联查询的结果集中的对象类型即List中的对象类型。
上面的resultMap userorderdetailmap 可以继承userordermap ,复用重复部分
"cn.com.model.Orders" id="userorderdetailmap" extends="userordermap">
property="orderdetails" ofType="cn.com.model.Orderdetail">
<id property="id" column="orderdetail_id" />
<result property="itemsId" column="items_id" />
<result property="itemsNum" column="items_num" />
resultMap 中用 extends=”父resultMap” 可复用已有的resultMap中的映射配置
需要关联查询映射的信息是:用户、订单、订单明细、商品信息
订单:一个用户对应多个订单,使用collection映射到用户对象的订单列表属性中
订单明细:一个订单对应多个明细,使用collection映射到订单对象中的明细属性中
商品信息:一个订单明细对应一个商品,使用association映射到订单明细对象的商品属性中
PO类
public class User {
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
//一个用户对应多个订单
private List orders = new ArrayList();
}
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息
private User user;
//订单明细
private List orderdetails;
。。
}
public class Orderdetail {
private Integer id;
private Integer ordersId;
private Integer itemsId;
private Integer itemsNum;
private Items items;
。。。。
}
映射文件
"cn.com.model.User" id="userOrderListResultMap">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
property="orders" ofType="cn.com.model.Orders">
<id column="id" property="id"/>
<result property="number" column="number"/>
property="user" javaType="cn.com.model.User">
<id property="id" column="user_id" />
<result property="username" column="username" />
<result property="address" column="address" />
property="orderdetails" ofType="cn.com.model.Orderdetail">
<id column="orderdetail_id" property="id"/>
<result property="ordersId" column="id"/>
<result property="itemsId" column="items_id"/>
<result property="itemsNum" column="items_num"/>
property="items" javaType="cn.com.model.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_detail" property="detail"/>
需要查询关联信息时,使用mybatis延迟加载特性可有效的减少数据库压力,首次查询只查询主要信息,关联信息(如订单用户关系,可先查询订单,需要用户信息)获取时再加载。
在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading
设置项 | 描述 | 允许值 | 默认值 |
---|---|---|---|
lazyLoadingEnabled | 全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载 | true,false | false |
aggressiveLazyLoading | 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载 | true ,false | true |
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
PO类
一个用户可以有多个订单,多个订单归属一个用户
订单与用户是多对一关系,在订单实体类中增加User的属性
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息
private User user;
。。。。。
}
映射文件
在Orders的映射文件中,通过association 配置关联属性,此处不在配置User的各个属性映射
增加select 和 colum属性配置
select=”cn.com.model.UserDao.findUserById”
在association 中配置select属性,指定懒加载关联查询使用的statement,findUserById在user.xml中,所以此处加上命名空间
column=”user_id”
在association 中配置column属性,指定懒加载关联查询使用的statement中需要传入的值
<mapper namespace="cn.com.dao.OrdersDao">
<resultMap type="cn.com.model.Orders" id="orderLazyUser">
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
<association property="user" javaType="cn.com.model.User"
select="cn.com.model.UserDao.findUserById" column="user_id">
association>
resultMap>
<select id="findOrdersLazyLoadUser" resultMap="orderLazyUser">
SELECT id,user_id,number,createtime,note FROM orders
select>
mapper>
此处 的findUserById 在orders映射文件中使用到
namespace="cn.com.model.UserDao">
<select id="findUserById" parameterType="int" resultType="cn.com.model.User">
SELECT * FROM USER WHERE id=#{value}
select>
测试类
@Test
public void findOrdersLazyLoadUser() throws Exception{
String resource = "sqlmapconfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class);
List list = ordersDao.findOrdersLazyLoadUser();
for(Orders orders:list){
System.out.println(orders.getUser().getUsername());
}
sqlSession.close();
}
此处在System.out.println(orders.getUser().getUsername());才会查询数据库,加载User的值
Mybatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。
Mybatis二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。
一级缓存区域是根据SqlSession为单位划分的。
同一个SqlSession每次查询会先从缓存区域找,如果找不到再从数据库查询,查询到数据将数据写入缓存。下一次再次执行相同的查询时,则会从缓存中取出,不再查询数据库。
Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象
sqlSession执行insert、update、delete等操作commit提交后会清空缓存区域。
一级缓存是SQLSession级别的缓存。默认是开启的。
- 测试一级缓存
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//第一次查询
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//第二次查询,由于是同一个session则不再向数据发出语句直接从缓存取出
User user2 = userMapper.findUserById(1);
System.out.println(user2);
//关闭session
session.close();
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//第一次查询
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//在同一个session执行更新
user1 .setUsername("xxx");
userMapper.updateUser(user1 );
session.commit();
//第二次查询,虽然是同一个session但是由于执行了更新操作session的缓存被清空,这里重新发出sql操作
User user2 = userMapper.findUserById(1);
System.out.println(user2);
二级缓存区域是根据mapper的namespace划分的,相同namespace的mapper查询数据放在同一个区域。
每一个namespace会有一个自己的二级缓存,不同的 namespace用不同的二级缓存。
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。
每次查询会先从缓存区域找,如果找不到从数据库查询,查询到数据将数据写入缓存
在SqlMapConfig.xml设置二级缓存的总开关默认是开启的,但是建议还是配置开启。
在核心配置文件SqlMapConfig.xml中加入
"cacheEnabled" value="true"/>
配置项 | 描述 | 允许值 | 默认值 |
---|---|---|---|
cacheEnabled | 对在此配置文件下的所有cache 进行全局性开/关设置 | true,false | true |
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。
在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。
<mapper namespace="cn.com.dao.OrdersDao">
<cache type=""/>
type指定实现mybatis cache 接口的实现类 类名,默认是org.apache.ibatis.cache.impl.PerpetualCache
为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一样在内存。
public class Orders implements Serializable{
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息
private User user;
。。
}
String resource = "sqlmapconfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
SqlSession sqlSession1 = sqlSessionFactory.openSession();
OrdersDao ordersDao1 = sqlSession1.getMapper(OrdersDao.class);
//第一次查询,缓存中没数据,请求数据库查询
Orders orders1 = ordersDao1.findById(3);
//sqlsession关闭
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
OrdersDao ordersDao2 = sqlSession2.getMapper(OrdersDao.class);
//第二次查询,缓存中有数据,从缓存中取出数据,不再请求数据库查询
Orders orders2 = ordersDao2.findById(3);
sqlSession2.close();
String resource = "sqlmapconfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
SqlSession sqlSession1 = sqlSessionFactory.openSession();
OrdersDao ordersDao1 = sqlSession1.getMapper(OrdersDao.class);
//第一次查询,缓存中没数据,请求数据库查询
Orders orders1 = ordersDao1.findById(3);
//sqlsession关闭
sqlSession1.close();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
OrdersDao ordersDao3 = sqlSession3.getMapper(OrdersDao.class);
//第二次查询,缓存中有数据,从缓存中取出数据,不再请求数据库查询
Orders orders3 = ordersDao3.findById(3);
orders3.setCreatetime(new Date());
ordersDao3.updateOrder(orders3);
sqlSession3.commit();
//执行提交,清空OrderMapper下边的二级缓存,防止脏读
sqlSession3.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
OrdersDao ordersDao2 = sqlSession2.getMapper(OrdersDao.class);
//第三次查询,缓存中没有数据,请求数据库查询
Orders orders2 = ordersDao2.findById(3);
sqlSession2.close();
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findById" useCache="false" parameterType="int" resultMap="orderLazyUser">
在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache=”true” 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。
ehcache是一个分布式缓存框架。我们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)
不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统 开发。所以要使用分布式缓存对缓存数据进行集中管理。
mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
package org.apache.ibatis.cache;
import java.util.concurrent.locks.ReadWriteLock;
public interface Cache {
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
ReadWriteLock getReadWriteLock();
}
mybatis默认实现cache类是:
package org.apache.ibatis.cache.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
/**
* @author Clinton Begin
*/
public class PerpetualCache implements Cache {
private String id;
private Map
下载地址:http://download.csdn.net/detail/hxskmx/8802683
ehcache实现mybatis cache接口 实现类
配置mapper中cache中的type为ehcache对cache接口的实现类型。
namespace="cn.congxing.model.User">
type="org.mybatis.caches.ehcache.EhcacheCache"/>
在classpath下配置ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="F:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
defaultCache>
ehcache>
http://download.csdn.net/detail/hxskmx/8802897
generatorConfig.xml
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="true" />
commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="123">
jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
javaTypeResolver>
<javaModelGenerator targetPackage="cn.congxing.model"
targetProject=".\src">
<property name="enableSubPackages" value="false" />
<property name="trimStrings" value="true" />
javaModelGenerator>
<sqlMapGenerator targetPackage="cn.congxing.model"
targetProject=".\src">
<property name="enableSubPackages" value="false" />
sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.congxing.dao"
targetProject=".\src">
<property name="enableSubPackages" value="false" />
javaClientGenerator>
<table tableName="items">table>
<table tableName="orders">table>
<table tableName="orderdetail">table>
<table tableName="user">table>
context>
generatorConfiguration>
package cn.congxing.test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class GeneratorSqlmap {
public void generator() throws Exception{
List warnings = new ArrayList();
boolean overwrite = true;
//指定 逆向工程配置文件
File configFile = new File("config/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) throws Exception {
try {
GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
generatorSqlmap.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}