Teacher表
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='老师表';
-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES ('1', 'radan');
INSERT INTO `teacher` VALUES ('2', 'js');
Student表
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`tid` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `tid` (`tid`),
CONSTRAINT `tid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', '张三', '1');
INSERT INTO `student` VALUES ('2', '李四', '1');
INSERT INTO `student` VALUES ('3', '王五', '1');
INSERT INTO `student` VALUES ('4', '溜溜', '1');
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private int id;
private String name;
}
public class Student {
private int id;
private String name;
// 学生需要关联一个老师
private Teacher teacher;
}
<resultMap id="studentAndTeacher" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
resultMap>
<select id="getAllStudents" resultMap="studentAndTeacher">
select * from student
select>
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
select>
注意点:就是当要联立的两张表都有相同的字段名时,会起“冲突”,导致查询的结果都是前面一张表的字段属性值
解决思路:在编写sql语句时,给冲突的列起别名,然后在resultMap结果集映射中利用别名可以有效的避免冲突。
<select id="getAllStudents2" resultMap="studentMap">
select s.id sid,s.name sname, t.name tname, t.id t_id from student s,teacher t where s.tid=t.id
select>
<resultMap id="studentMap" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="teacher">
<result property="id" column="t_id"/>
<result property="name" column="tname"/>
association>
resultMap>
例如:一个老师拥有多个学生
对于老师而言就是一个一对多的处理。
public class Teacher {
private int id;
private String name;
//一个老师拥有多个老师
List<Student> students;
}
public class Student {
private int id;
private String name;
//学生只有一个老师
private int tid;
}
<!-- 按照结果嵌套查询-->
<resultMap id="teacherMap" type="teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--
复杂的属性:单独处理。 我们需要单独处理的是 对象:association 集合:collection
javaType=“” 填的都是指定属性的类型
在集合中一般都是泛型信息,使用ofType获取
-->
<collection property="students" ofType="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
<select id="getAllTeacher" resultMap="teacherMap">
select s.id sid,s.name sname,t.id tid,t.name tname
from teacher t,student s where s.tid=t.id
</select>
<select id="getTeacher2" resultMap="teacherMap2">
select * from teacher where id=#{id}
select>
<resultMap id="teacherMap2" type="teacher">
<collection property="students" javaType="ArrayList" ofType="student" column="id" select="getStudentByTeacher_id">
collection>
resultMap>
<select id="getStudentByTeacher_id" parameterType="int" resultType="student">
select * from student where tid=#{tid}
select>
总结:
注意点:
动态Sql:就是指根据不同的条件生成不同的SQL语句
DROP TABLE IF EXISTS `blog`;
CREATE TABLE `blog` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`title` varchar(255) DEFAULT NULL COMMENT '博客标题',
`author` varchar(255) DEFAULT NULL COMMENT '博客作者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`views` int DEFAULT NULL COMMENT '浏览量',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='博客表';
-- ----------------------------
-- Records of blog
-- ----------------------------
INSERT INTO `blog` VALUES ('1', '游戏', 'randan', '2023-06-30 17:22:07', '1');
INSERT INTO `blog` VALUES ('2', '日志', 'radan', '2023-10-30 17:21:21', '22');
INSERT INTO `blog` VALUES ('3', '兰州牛肉面', 'js', '2023-06-30 17:21:20', '33');
<select id="queryBlog" parameterType="map" resultType="blog">
select * from blog where 1=1
<if test="title != null ">
and title=#{title}
if>
<if test="author != null ">
and author=#{author}
if>
select>
这个标签像Switch,Case语法的使用规则。(模糊查找,提供了什么就查询这些条件符合的记录)。
只能选择一个 按照顺序来判断
<select id="queryBlogChoose2" parameterType="map" resultType="blog">
select * from blog
<where>
<choose>
<when test="title !=null">
title=#{title}
when>
<when test="author != null">
and author=#{author}
when>
<otherwise>
and views =#{views}
otherwise>
choose>
where>
select>
Where
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from blog
<where>
<if test="title != null ">
and title=#{title}
if>
<if test="author != null ">
and author=#{author}
if>
where>
Set(注意:必须有一个if成立,不然就会导致update语句后面没有set更新的值。)
<update id="updateBlog" parameterType="map" >
update blog
<set>
<if test="title != null">title=#{title},if>
<if test="author != null">author=#{author}if>
set>
where id=#{id}
update>
<select id="queryBlogForEach" parameterType="map" resultType="blog">
select * from blog
<where>
<foreach collection="ids" index="index" item="id" open=" and (" close=")" separator="or">
id = #{id}
foreach>
where>
测试:
@org.junit.Test
public void test006() throws IOException {
SqlSession sqlSession= MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map=new HashMap();
List<Integer> ids=new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
map.put("ids",ids);
System.out.println(mapper.queryBlogForEach(map));
sqlSession.commit();
sqlSession.close();
}
作用:将重复的SQL语句抽取出来,放到标签中,可以进行复用。
<sql id="title-author">
<if test="title != null ">
and title=#{title}
if>
<if test="author != null ">
and author=#{author}
if>
sql>
<select id="queryBlog" parameterType="map" resultType="blog">
select * from blog where 1=1
<include refid="title-author">include>
select>
注意事项:
查询数据–>连接数据库,好资源!
什么是缓存[Cache]?
什么样的数据能使用缓存
MyBatis 包含了一个非常强大的查询缓存特性,他可以非常方便地定制和配置缓存,缓存可以极大的提升查询效率。
MyBatis 系统中默认定义了两级缓存:以及缓存和二级缓存
测试步骤:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
@Test
public void test001() throws IOException {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allUsers = mapper.getAllUsers();
List<User> users = allUsers;
System.out.println(users==allUsers);
sqlSession.close();
}
sqlSession.clearCache();//清理缓存
小结:一级缓存默认是开启的,只在一次SQLSession中有效,也就是拿到连接到关闭连接的区间。
步骤:
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
@Test
public void test002() throws IOException {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
SqlSession sqlSession1 = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.findUserById(1);
sqlSession.close();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
User user2 = mapper1.findUserById(1);
System.out.println(user1==user2);
sqlSession1.close();
}
注意点:
二级缓存存在于 SqlSessionFactory 生命周期中。
我一直以为二级缓存针对的对象是一个Mapper对象,只要是针对同一个Mapper的操作,都可以实现二级缓存。但是前提是操作必须在同一个SqlSessionFactory 中进行。
在一开始的代码中,通过调用三次getFactory()并打开session,实例化了三个不同的SqlSessionFactory 对象,这样在后续的SQL操作中,是不可能命中二级缓存的。
Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存。
要在程序中使用,先导入依赖
<dependency>
<groupId>org.mybatis.cachesgroupId>
<artifactId>mybatis-ehcacheartifactId>
<version>1.2.1version>
dependency>
在mapper.xml中使用对应的缓存即可
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
编写ehcache.xml文件,如果在 加载时 未找到 /ehcache.xml 资源或出现问题,则将使用默认配置。
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false" dynamicConfig="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>
测试结果还是和之前一样的。
问题描述:当我们在mybatis的配置文件中,写好绑定Mapper.xml文件时,运行结果依旧提示找不到Mapper.xml或是没有绑定。
MyBatis 配置信息:
错误信息:
此时,我们可以查看target目录下的class文件夹,发现并没有编译出UserMapper.xml文件。
解决方法:主要原因就是Maven在导出资源失败,资源过滤出现问题。我们需要在pom.xml中添加防止一些指定的资源文件的过滤配置。
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>