mybatis体系结构
开发步骤
配置文件
mybatis.xml
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/java?"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="xxx"> <insert id="insertTeacher" parameterType="com.mybatisLearn.beans.Teacher">
insert into teacher(name,age,lesson) values (#{name},#{age},#{lesson})
</insert>
</mapper>
它根据传进来的类的属性来找值,属性是指实现了get set方法的。
一个简单的Teacher实体类,该类用来定义表的结构,对于必要的属性,必须实现get set方法。
package com.mybatisLearn.beans; public class Teacher { private String name; private Integer age; private String lesson;
//记得实现一个无参方法,不然mybatis只会调用有参构造器,从而报错。
public Teacher(){}
public Teacher(String name, Integer age, String lesson) { this.name = name; this.age = age; this.lesson = lesson; } @Override public String toString() { return "Teacher{" + "name='" + name + '\'' + ", age=" + age + ", lesson='" + lesson + '\'' + '}'; } public String getName() {return name;} public void setName(String name) {this.name = name;} public Integer getAge() {return age;} public void setAge(Integer age) {this.age = age;} public String getLesson() {return lesson;} public void setLesson(String lesson) {this.lesson = lesson;} }
Dao层的实现
package com.mybatisLearn.dao;
import com.mybatisLearn.beans.Teacher;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class ITeacherDaoImpl implements ITeacherDao {
@Override
public void insert(Teacher teacher) {
SqlSession sqlSession = null;
try {
// 加载主配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
// 创建sqlsessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 创建sqlSession
sqlSession = sqlSessionFactory.openSession();
// 操作
sqlSession.insert("insertTeacher", teacher);
// 提交操作
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
测试一下
package com.mybatisLearn.Test; import com.mybatisLearn.beans.Teacher; import com.mybatisLearn.dao.ITeacherDao; import com.mybatisLearn.dao.ITeacherDaoImpl; import org.junit.Before; import org.junit.Test; public class ATest { private ITeacherDao dao; @Before public void before(){ dao = new ITeacherDaoImpl(); } @Test public void test(){ Teacher teacher = new Teacher("李花",22,"人工智能"); dao.insert(teacher); } }
Done!
Mapper中namespace
当多个mapper文件中有重名的sql时,会报错
Error updating database. Cause: java.lang.IllegalArgumentException: insertTeacher is ambiguous in Mapped Statements collection (try using the full name including the namespace, or rename one of the entries)
需要指明使用
sqlSession.insert("test01.insertTeacher", teacher);
从属性文件中读取jdbc连接要素
jdbc_mysql.properties
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/java?serverTimezone=GMT%2B8 jdbc.username=root jdbc.password=baobao521
mybatis.xml
<properties resource="jdbc_mysql.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
别名
mapper.xml 中每条语句都要写parameterType太冗余,可以使用别名
在mybatis.xml中配置
<typeAliases> <typeAlias type="com.mybatisLearn.beans.Teacher" alias="Teacher"/> </typeAliases>
mapper.xml中可以简写
<insert id="insertTeacher" parameterType="Teacher">
insert into teacher(name,age,lesson) values (#{name},#{age},#{lesson})
</insert>
但是每个表都要写的话还是很冗余,使用package可以更简单,可以将包中的简单类名当作别名。
<typeAliases>
<package name="com.mybatisLearn.beans"/>
</typeAliases>
使用别名解决字段不一致问题
有时候,实体类的字段名和属性名可能不一致,这时可以通过别名来解决
<select id="xx" resultType="Teacher">
select tid id, tname name, tage age from teacher
</select>
使用resultmap来解决不一致问题
<resultMap id="studentMapper" type="Student"> <id column="id" property="id"></id> <result column="sname" property="age"></result> <result column="sname" property="name"></result> </resultMap>
实现mapper的动态代理
// 通过sqlSession中的getMapper方法来动态加载Dao类,
sqlSession = MyBatisUtils.getSqlSession(); studentdao = sqlSession.getMapper(IStudentDao.class);
// 保证命名一致, 只需调用mapper中注册方法的id就可以
List<Student> students = studentdao.queryAll();
使用Map实现多条件查询
Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "李"); map.put("age",15); List<Student> students = studentdao.queryMuti(map);
<select id="queryMuti" resultType="Student"> select name,age,id from student where name like '%' #{name} '%' and age > #{age} </select>
使用索引号实现多条件查询
List<Student> students = studentdao.queryMuti2("李", 15);
<select id="queryMuti2" resultType="Student">
select name,age,id from student where name like '%' #{arg0} '%' and age > #{arg1}
</select>
动态SQL
<mapper namespace="com.DymicSqlLearn.Dao.IUserDao">
<select id="selectStudentByCondition" resultType="User">
select id, username, password, role
from user
<where>
<if test="arg0 != null and arg0 != ''">
and username like '%' #{arg0} '%'
</if>
<if test="arg1 > 0">
and role < #{arg1}
</if>
</where>
</select>
</mapper>
一些符号不能使用需要替换
< <= > >= & ' "
< <;= > >= & ' "
choose的行为类似于switch
<select id="queryByChoose" resultType="User"> select * from user <where> <choose> <when test="arg0 != null and arg0 != ''"> and username like '%' #{arg0} '%' </when> <when test="arg1 > 0"> and role < #{arg1} </when> </choose> </where> </select>
foreach
<select id="quertByForeach" resultType="User"> select * from user <if test="array.length > 0"> where id in <foreach collection="array" item="roleid" open="(" close=")" separator=","> #{roleid} </foreach> </if> </select>
foreach-list
<select id="quertByForeachList" resultType="User"> select * from user <if test="list.size > 0"> where id in <foreach collection="array" item="roleid" open="(" close=")" separator=","> #{roleid} </foreach> </if> </select>
SQL片段
<sql id="parms">
id, username, password, role
</sql>
select <include refid="parms"></include>from user
一对多
简化版
public class User { private Set<Article> articles; }
public class Article { private User author; }
查询
<resultMap id="userMapper" type="com.foreignkeyMybatis.beans.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<collection property="articles" ofType="com.foreignkeyMybatis.beans.Article">
<id column="aid" property="id"/>
<result column="title" property="title"/>
</collection>
</resultMap>
<select id="getAll" resultMap="userMapper">
select user.id, username, title, uid, aid
from user, article
where uid = user.id
</select>
或者也可以
<select id="selectArtByUid" resultType="com.foreignkeyMybatis.beans.Article"> select title from article where uid=#{xxx} </select> <resultMap id="userMapper2" type="com.foreignkeyMybatis.beans.User"> <id column="id" property="id"/> <result column="username" property="username"/> <collection property="articles" ofType="com.foreignkeyMybatis.beans.Article" select="selectArtByUid" column="id"> </collection> </resultMap> <select id="getByName" parameterType="string" resultMap="userMapper2"> select id, username from user where username=#{xxx} </select>
当多对一时,只需将collection替换成associate就可以
懒加载
mybatis.xml 中配置, 必须是多次查询。
侵入式懒加载
<settings> <!-- 访问实体时才触发加载, 实体内的关联表作为实体的一部分--> <setting name="lazyLoadingEnable" value="true"/> <setting name="aggresiveLayLoading" value="false"/> </settings>
深度懒加载
<settings> <!-- 访问实体内的关联表时才触发加载--> <setting name="lazyLoadingEnable" value="true"/> <setting name="aggresiveLayLoading" value="true"/> </settings>
缓存
- 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 SQLSession,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。默认开启
2.二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
二级缓存开启
<mapper namespace="com.cache.dao.IUserDao"> <!-- 开启二级缓存 --> <cache/>
</mapper>
常用属性
<cache eviction="FIFO" <!--回收策略为先进先出--> flushInterval="60000" <!--自动刷新时间60s--> size="512" <!--最多缓存512个引用对象--> readOnly="true"/>
使用ehcache缓存
需要 mybatis-ehcache.jar 和 ehcache-core.jar
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
配置
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" 内存中缓存的element的最大数目 maxElementsOnDisk="10000000" 磁盘上缓存的element的最大数目 eternal="false" 设定缓存的elements是否永远不过期 overflowToDisk="false" 内存缓存溢出的时候是否将过期的element缓存到磁盘上 timeToIdleSeconds="120" 两次访问的间隔时间,超过便被删除 timeToLiveSeconds="120" 缓存element的有效生命期 diskExpiryThreadIntervalSeconds="120" 磁盘缓存的清理线程运行间隔,默认是120秒 memoryStoreEvictionPolicy="LRU"> 内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略 </defaultCache> </ehcache>