mybatis配置文件解析说明
1.中的logImpl属性配置指定使用LOG4J输出日志
2.元素配置一个包的别名,通常确定一个类的时候需要使用类的全限定名称,配置别名后,在使用类的时候不需要写包名的部分
3.环境配置中主要配置了数据库连接
mybatis-config配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
<!--数据库中使用user_name,java属性使用userName,这种方式,开启下面的配置,可以实现不需要别名和resultMap达到自动映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<package name="com.picc.mybatis.model"></package>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.2.253:3306/mytest"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--这种方式适用没有接口的时候,很繁琐-->
<mappers>
<mapper resource="mapper/CountryMapper.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/RoleMapper.xml"/>
<mapper resource="mapper/RolePrivilegeMapper.xml"/>
<mapper resource="mapper/UserRoleMapper.xml"/>
<mapper resource="mapper/PrivilegeMapper.xml"/>
</mappers>
<!--这种方式使用于有接口的方式,而且简单,,查找包下所有的接口
循环对接口进行如下操作
1.判断接口对应的命名空间是否存在
2.加载接口对应的xml文件,将接口权限定名转化为路径,搜索。xml后缀的资源,找到就解析xml
-->
<mappers>
<package name="com.picc.mybatis.mapper"></package>
</mappers>
userMapper.xml配置文件
<?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接口和xml关联的时候,namespace需要设置成接口的权限定名称,mybatis内部通过这个命名空间将接口和xml关联起来-->
<mapper namespace="com.picc.mybatis.mapper.UserMapper">
<!--resultMap通过设置列和属性的对应关系来实现查询列自动映射到属性的,除了这种方式还可以在查询语句中使用别名来达到自动映射的功能-->
<!--resultmap只是用来完成字段映射的功能,当返回类型使用resulttype的时候,使用别名的来映射-->
<resultMap id="userMap" type="SysUser">
<!--通过构造方法注入-->
<constructor>
<idArg column="id" javaType="long"></idArg>
<arg column="user_name" javaType="String"></arg>
</constructor>
<!--通过setter方式注入-->
<result property="userPassword" column="user_password"></result>
<result property="userEmail" column="user_email"></result>
<result property="userInfo" column="user_info"></result>
<result property="headImg" column="head_img" jdbcType="BLOB"></result>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"></result>
</resultMap>
<resultMap id="roleMap" type="SysRole">
<!--多表关联查询,字段映射可以通过下面的方式来实现对象的映射-->
<association property="user" resultMap="userMap"></association>
</resultMap>
<select id="selectById" resultMap="userMap">
SELECT * FROM sys_user where id = #{id};
</select>
<!--当多表关联查询的时候,可以将语句写在相关表对应的任意一个xml中
-->
<select id="selectAll" resultType="SysUser">
SELECT id, user_name userName, user_password userPassword,user_email userEmail,
user_info userInfo,head_img headImg,create_time createTime
from sys_user;
</select>
<!--多表查询,可以在涉及的多表中任何一个表中创建一下语句,如果要映射多表的数据,则需要在role中创建user属性-->
<select id="selectRolesByUserId" resultType="SysRole">
select r.id,r.role_name roleName,r.enabled,r.create_by createBy,
r.create_time createTime,u.user_name as "Sysuser.userName",
u.user_email as "Sysuser.userEmail"
from sys_user u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on r.id = ur.role_id
where u.id= #{uid}
</select>
<!--useGeneratedKeyss设置为true,来取出由数据库内部生成的主键的值,将其赋值给keyProperty配置的id值,但是只支持主键自增的主键的数据库-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into sys_user (id, user_name, user_password, user_email,user_info, head_img, create_time) values (#{id} , #{userName} , #{userPassword} , #{userEmail} ,#{userInfo} , #{headImg, jdbcType=BLOB},
#{createTime, jdbcType= TIMESTAMP})
</insert>
<!--这种方式即支持主键自增的数据库,也支持非自增的数据库,在mysql中order="AFTER",
因为主键值在插入成功后才能获取,而oracle先从序列获取值,然后作为主键插入order="before"
-->
<insert id="insertUser2">
insert into sys_user (id, user_name, user_password, user_email,user_info, head_img, create_time) values (#{id} , #{userName} , #{userPassword} , #{userEmail},
#{userInfo} , #{headImg, jdbcType=BLOB},
#{createTime, jdbcType= TIMESTAMP})
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
</insert>
</mapper>
public class CountryMapperTest {
private static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void init() throws Exception{
//通过Resources将配置文件读取到reader
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//在创建sqlSessionFactory的过程中,解析mybatis-config中的信息,读取到mapper时,将mapper.xml全部读取进行具体方法的解析,极细完之后,sqlSessionFactory就包含了所有的属性配置和sql信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
}
public SqlSession getSqlSession(){
//sqlSesiion默认不开启自动提交
return sqlSessionFactory.openSession();
}
@Test
public void testSelectAll(){
SqlSession sqlSession = getSqlSession();
try {
//只有xml,不和接口关联的情况,使用下面的语句
List<Country> countryList = sqlSession.selectList ("selectall");
System.out.println(countryList.get(0).getCountryname());
} finally {
sqlSession.close();
}
// 接口和xml关联的情况
@Test
public void testselectRolesByUserId() {
SqlSession sqlSession = getSqlSession();
try {
// 创建接口的代理对象,对象名称以$proxy123表示
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用接口中的方法
List<SysRole> sysRole = mapper.selectRolesByUserId(1);
System.out.println(sysRole.get(0).getUser().getUserName());
} finally {
sqlSession.close();
}
}
}
mybatis缓存配置
一级缓存
mybatis的一级缓存存在于sqlsession的生命周期中,在同一个sqlsession中查询时,mybatis会把执行的方法和参数通过算法生成缓存的键值,将键值和结果存在一个map对象中。如果同一个sqlsession中执行的方法和参数完全一致,那么通过算法会生成相同的键值,当map缓存对象中已经存在该键值时,则会返回缓存中的对象。
<select id=”selectByid” flushCache=”true” resultMap=’”userMap”>
</select>
flushCache=true会在查询数据前,清空当前的一级缓存,因此该方法每次都会重新从数据库中查询数据。。任何的insert update delete操作都会清空一级缓存
二级缓存
mybatis 的二级缓存存在于sqlsessionFactory的生命周期中,在mybatis-config.xml设置下面的配置
<settings>
<setting name=”cacheEnabled” value=”true” />
</settings>
cacheEnabled设置为true,二级缓存开启
mybatis的二级缓存是和命名空间绑定的,即二级缓存需要配置在Mapper.xml映射文件中,或者配置在mapper.java接口中
<?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="com.picc.mybatis.mapper.UserMapper">
<cache/>
</mapper>
默认的二级缓存有以下的效果
1.映射文件中的所有select语句将会被缓存。
2.映射文件中的所有insert update delete语句会刷新缓存
3.缓存会使用LRU最近最少使用的算法来收回
4.缓存会存储集合或对象的1024个引用
5.缓存会被视为 read/write (可读/可写)的,意味着对象检索不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
6.根据时间表(如 no Flush Interval ,没有刷新间隔),缓存不会以任何时间顺序来刷新。
所有的这些属性都可以通过缓存元素的属性来修改
属性介绍:
evicion(收回策略)
LRU(最近最少使用的):移除最长时间不被使用的对象,这是默认值。
FIFO(先进先出):按对象进入缓存的顺序来移除它们。
SOFT(软引用):移除基于垃圾回收器状态和软引用规则的对象。
WEAK(弱引用):更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushinterval(刷新间隔)
可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况不设置,即没有刷新间隔,缓存仅仅在调用语句时刷新。
size(引用数目)
可以被设置为任意正整数,要记住缓存的对象数目和运行环境的可用内存资源数目。默认值是1024 。
readOnly(只读)
属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改,这提供了很重要的性能优势。
可读写的缓存会通过序列化返回缓存对象的拷贝,这种方式会慢一些,但是安全,因此默认是 false。
readOnly=true只读,二级缓存会返回相同的实例,使用map来存储缓存值
readOnly=false可读写的缓存,使用SerializedCache序列化缓存来实现可读写缓存类,并通过序列化和反序列化来保证通过缓存获取数据时,得到是一个新的实例
ration 缓存命中率
@Test
public void testUserSelectByid() {
SqlSession sqlSession = getSqlSession();
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
SysUser sysUser = mapper.selectById(1);
sysUser.setUserName("haha");
System.out.println(sysUser.getUserName()); //haha
SysUser sysUser1 = mapper.selectById(1);
System.out.println(sysUser1.getUserName()); //haha
System.out.println(sysUser==sysUser1); //true
} finally {
sqlSession.close();
}
SqlSession sqlSession1 = getSqlSession();
try {
UserMapper mapper = sqlSession1.getMapper(UserMapper.class);
SysUser sysUser = mapper.selectById(1);
System.out.println(sysUser.getUserName()); //haha
SysUser sysUser1 = mapper.selectById(1);
System.out.println(sysUser1.getUserName()); //haha
System.out.println(sysUser==sysUser1); //true
} finally {
sqlSession.close();
}
}
命中率
mutates提供的缓存是基于map实现的内存缓存,当需要缓存大量数据的时候,不能仅仅通过提高内存来使用mybatis的二级缓存,还可以通过EhCache缓存框架或redis缓存数据库来实现二级缓存