多个学生,对应一个老师java
对于学生这边而言,关联多个学生,关联一个老师 【多对一】git
对于老师而言,集合,一个老师又不少学生 【一对多】github
@Data @NoArgsConstructor @AllArgsConstructor public class teacher { private int id; private String name; }
@Data @NoArgsConstructor @AllArgsConstructor public class student { private int id; private String name; private teacher teacher; }
public interface StudentMapper { public List<student> getStudent(); }
思路:算法
复杂的对象就用association
和collection
sql
对象:association
集合:collection
数据库
<mapper namespace="com.Dao.StudentMapper"> <resultMap id="stutea" type="pojo.student"> <result property="id" column="id"/> <result property="name" column="name"/> <association property="teacher" column="tid" javaType="pojo.teacher" select="getTeacher"/> </resultMap> <select id="getStudent" resultMap="stutea"> select * from mybatistest.stu </select> <select id="getTeacher" resultType="pojo.teacher"> select * from mybatistest.teacher where id = #{id} </select> </mapper>
<mapper namespace="com.Dao.StudentMapper"> <select id="getStudent" resultMap="studentTeacher2"> select s.id,s.name,t.name from mybatistest.stu s,mybatistest.teacher t where s.tid=t.id </select> <resultMap id="studentTeacher2" type="pojo.student"> <result property="id" column="id"/> <result property="name" column="name"/> <association property="teacher" javaType="pojo.teacher"> <result property="name" column="name"/> </association> </resultMap> </mapper>
@Test public void getStudent(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<student> student = mapper.getStudent(); for (pojo.student student1 : student) { System.out.println(student1); } sqlSession.close(); }
数据库不变
缓存
@Data @NoArgsConstructor @AllArgsConstructor public class teacher { private int id; private String name; private List<student> students; }
@Data @NoArgsConstructor @AllArgsConstructor public class student { private int id; private String name; // private teacher teacher; private int tid; }
public interface TeacherMapper { public teacher getTeacher(@Param("tid") int id); }
<mapper namespace="com.Dao.TeacherMapper"> <select id="getTeacher" resultMap="geTeacher" > select * from mybatistest.teacher where id = #{tid} </select> <resultMap id="geTeacher" type="pojo.teacher"> <collection property="students" javaType="ArrayList" ofType="pojo.student" select="getStudent" column="id"></collection> </resultMap> <select id="getStudent" resultType="pojo.student"> select * from mybatistest.stu where tid = #{tid} </select> </mapper>
<mapper namespace="com.Dao.TeacherMapper"> <select id="getTeacher" resultMap="teacherStudent"> select t.id tid,t.name tname,s.id sid,s.name sname from mybatistest.stu s,mybatistest.teacher t where s.tid=t.id and t.id=#{tid} </select> <resultMap id="teacherStudent" type="pojo.teacher"> <result property="id" column="tid"/> <result property="name" column="tname"/> <collection property="students" ofType="pojo.student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <result property="tid" column="tid"/> </collection> </resultMap> </mapper>
@Test public void getTeacher(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); teacher teacher = mapper.getTeacher(1); System.out.println(teacher); sqlSession.close(); }
ofType & javaType安全
javaType
用来指定实体类中属性ofTyoe
用来指定映射到List或者集合中pojo类型,泛型中的约束类型注意点:注意一对多和多对一中,属性名和字段的问题mybatis
动态SQL就是指根据不一样的条件生成不一样的SQL语句app
CREATE TABLE `blog`( `id` INT(10) NOT NULL COMMENT '博客id', `title` VARCHAR(20) NOT NULL COMMENT '博客标题', `author` VARCHAR(10) NOT NULL COMMENT '做者', `create_time` DATETIME NOT NULL COMMENT '建立时间', `views` INT(20) NOT NULL COMMENT '浏览量' )ENGINE=INNODB CHARSET=utf8;
@Data @NoArgsConstructor @AllArgsConstructor public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }
public interface BlogMapper { public int addBlog(Blog blog); }
<mapper namespace="com.Dao.BlogMapper"> <insert id="addBlog" parameterType="pojo.Blog"> insert into mybatistest.blog(id,title,author,create_time,views) values (#{id},#{title},#{author},#{createTime},#{views}) </insert> </mapper>
@Test public void Test(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Blog blog = new Blog(1, "title", "张", new Date(), 11); int i = mapper.addBlog(blog); System.out.println(i); }
接口
public interface BlogMapper { public List<Blog> queryBlogIF(Map map); }
映射文件
<mapper namespace="com.Dao.BlogMapper"> <select id="queryBlogIF" parameterType="map" resultType="pojo.Blog"> select * from mybatistest.blog where 1=1 <if test="views != null"> and views > #{views} </if> <if test="author != null"> and author=#{author} </if> <if test="title != null"> and title like #{title} </if> </select> </mapper>
测试
@Test public void queryBlogIF(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap<String, Object> map = new HashMap<String, Object>(); map.put("views",10); List<Blog> blogs = mapper.queryBlogIF(map); for (Blog blog : blogs) { System.out.println(blog); } }
注意:
在配置文件中绑定:
<mappers> <mapper class="com.Dao.BlogMapper"/> </mappers>
这是由于在实体类中,数据库中定义时间属性为:create_time,有_
。
能够开启驼峰命名法映射,在配置文件中加入:
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
在数据库字段命名规范中经常用下划线 "_" 对单词进行链接,如:"create_time"
,而开发中实体属性一般会采用驼峰命名法命名为 createTime
。
接口
public interface BlogMapper { public List<Blog> queryBlogChoose(Map map); }
映射文件
<select id="queryBlogChoose" parameterType="map" resultType="pojo.Blog"> select * from mybatistest.blog <where> <choose> <when test="title != null"> and title like #{title} </when> <when test="author != null"> and author = #{author} </when> <otherwise> and views > #{views} </otherwise> </choose> </where> </select>
测试
@Test public void queryBlogChoose(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap<String, Object> map = new HashMap<String, Object>(); map.put("title","%啦%"); List<Blog> blogs = mapper.queryBlogChoose(map); for (Blog blog : blogs) { System.out.println(blog); } }
where
元素只会在子元素返回任何内容的状况下才插入 “WHERE” 子句。并且,若子句的开头为 AND
或 OR
,where 元素也会将它们去除。
<where> <if test="views != null"> views > #{views} </if> <if test="author != null"> and author=#{author} </if> <if test="title != null"> and title like #{title} </if> </where>
set
元素能够用于动态包含须要更新的列,忽略其它不更新的列。
接口
public int updateBlogSet(Map map);
映射文件
<update id="updateBlogSet" parameterType="map"> update mybatistest.blog <set> <if test="title != null">title=#{title},</if> <if test="author != null">author=#{author},</if> <if test="views != null">views=#{views},</if> </set> where id=#{id} </update>
测试
@Test public void updateBlogSet(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap<String, Object> map = new HashMap<String, Object>(); map.put("id",1); map.put("title","t-test"); map.put("author","a-test"); map.put("views",100); int i = mapper.updateBlogSet(map); System.out.println(i); HashMap map1 = new HashMap(); List<Blog> blogs = mapper.queryBlogIF(map1); for (Blog blog : blogs) { System.out.println(blog); } }
接口
public List<Blog> queryBlogForeach(Map map);
映射文件
<select id="queryBlogForeach" parameterType="map"> select * from mybatistest.blog <where> /*此处的collection是一个list,因此map须要传入一个list来进行遍历*/ <foreach collection="ids" item="id" open="and (" close=")" separator="or"> id=#{id} </foreach> <if test="views != null"> and views > #{views} </if> <if test="author != null"> and author=#{author} </if> </where> </select>
测试
@Test public void queryBlogForeach(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap<String, Object> map = new HashMap<String, Object>(); List<Integer> ids = new ArrayList<Integer>(); ids.add(2); ids.add(3); map.put("ids",ids); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } }
咱们能够将一些公共的部分用<sql>
抽取出来,方便复用!
<sql id="id-test"> <choose> <when test="title != null"> and title like #{title} </when> <when test="author != null"> and author = #{author} </when> <otherwise> and views > #{views} </otherwise> </choose> </sql> <select id="queryBlogChoose" parameterType="map" resultType="pojo.Blog"> select * from mybatistest.blog <where> <include refid="id-test"></include> </where> </select>
动态SQL
就是在拼接SQL语句,咱们只要保证SQL的正确性,按照SQL的格式,去排列组合就能够了
咱们能够先在Mysql中写出完整的SQL,在对应的去修改称为咱们的动态SQL
查询:链接数据库,耗资源!
一次查询的结果,给他暂存在一个能够直接取到的地方——内存:缓存
那么咱们再次查询的时候就能够不用走数据库了
Mybatis系统中默认顶一个两级缓存:一级缓存和二级缓存
注意事项:
- 映射语句文件中的全部 select 语句的结果将会被缓存。
- 映射语句文件中的全部 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不须要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(不管查询方法返回哪一种)的 1024 个引用。缓存会被视为读/写缓存,这意味着获取到的对象并非共享的,能够安全地被调用者修改,而不干扰其余调用者或线程所作的潜在修改。
一级缓存也叫本地缓存:
测试
@Test public void cache(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); user user = mapper.getUserById(1); System.out.println(user); System.out.println("==============================="); user user1 = mapper.getUserById(1); System.out.println(user1); System.out.println(user==user1); sqlSession.close(); }
从图中能够看出,数据在一级缓存,只查询一次,这二者相同,为true
手动清理缓存
@Test public void cache(){ SqlSession sqlSession = mybatis_util.getSqlSession1(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); user user = mapper.getUserById(1); System.out.println(user); sqlSession.clearCache(); //手动清理缓存 System.out.println("==============================="); user user1 = mapper.getUserById(1); System.out.println(user1); System.out.println(user==user1); sqlSession.close(); }
从图中能够看出,数据在一级缓存,手动清理缓存后,查询了两次,这二者不一样,为false
二级缓存是基于namespace的缓存,它的做用域比一级大
在配置文件开启二级缓存
<setting name="cacheEnabled" value="true"/>
在对应的mapper.xml
中选择开启二级缓存
<cache/>
也能够自定义cache
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
@Test public void SecondCache(){ SqlSession sqlSession = mybatis_util.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); user user = mapper.getUserByID(1); System.out.println(user); sqlSession.close(); System.out.println("==============================="); SqlSession sqlSession1 = mybatis_util.getSqlSession(); UserDao mapper1 = sqlSession1.getMapper(UserDao.class); user user1 = mapper1.getUserByID(1); System.out.println(user1); System.out.println(user==user1); sqlSession.close(); }
从图中能够看出,开启二级缓存后,sqlSession关闭时,数据存入二级缓存,直接在二级缓存调出数据,只用查询了一次 ,这二者不一样,为false
注意:可能会出现的错误:
Error serializing object. Cause:java.io.NotSerializableException: pojo.user
,这个错误只须要在实体类继承Serializable
,即:class user implements Serializable
Ehcache是一种普遍使用的开源Java分布式缓存。EhCache 是一个纯Java的进程内缓存框架,具备快速、精干等特色,是Hibernate中默认的CacheProvider。
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-ehcache --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.0.0</version> </dependency>
建立ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false"> <diskStore path="./tmpdir/Tmp_EhCache"/> <defaultCache eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="259200" memoryStoreEvictionPolicy="LRU"/> <cache name="cloud_user" eternal="false" maxElementsInMemory="5000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="1800" memoryStoreEvictionPolicy="LRU"/> </ehcache>
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
其实没什么大的区别,想用能够用