Mybatis
包结构
相关依赖
<!--导入依赖-->
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!--mybatis驱动-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--junit驱动-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<!--log4j依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--Lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!--spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
</dependencies>
<!--在build中配置resources,来防止我们的资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=utf-8
username=root
password=ROOT
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核心配置文件-->
<configuration>
<!--引入外部配置文件-->
<properties resource="db.properties">
<property name="pwd" value="ROOT"/>
</properties>
<settings>
<!--标准的日志工厂实现-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--是否开启自动驼峰命名规则(camel case)映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启全局缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
<!--可以给实体类起别名-->
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
<!--class文件绑定注册-->
<!-- <mapper resource="com/kuang/dao/UserMapper.xml"/>-->
<!--扫描包绑定-->
<!--<package name="com.kuang.dao"/>-->
</mappers>
</configuration>
- properties:导入外部资源,导入后可以直接在dataSource中使用,也可以在properties中通过property设置属性。
- mappers:有三种方式绑定Mapper文件
MybatisUtils工具类
package com.kuang.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//通过SqlSessionFactoryBuilder获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//通过SqlSessionFactory获取SqlSession
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);//设置为true自动提交事务!
}
}
IDUtils工具类
通过UUID的形式生成随机id
package com.kuang.util;
import java.util.UUID;
@SuppressWarnings("all") //抑制警告
public class IDUtils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
}
User实体类
package com.kuang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String password;
}
UserMappe接口
package com.kuang.dao;
import com.kuang.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Map;
public interface UserMapper {
List<User> selectUser();
List<User> getUserById(int id);
List<User> getUserListLikeName(String name);
int addUser(User user);
int updateUser(User user,int id);
int updateUserMap(Map<String,Object> map);
int deleteUser(int id);
@Update("delete from user where id=#{id}")
void deleteUser02(@Param("id") int id);
}
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 namespace="com.kuang.dao.UserMapper">
<!--查询全部用户-->
<select id="selectUser" resultType="User">
select * from user;
</select>
<!--根据id查询用户-->
<select id="getUserById" parameterType="int" resultType="User">
select * from user where id=#{id};
</select>
<!--通过name模糊查询-->
<!--也可以把"%"#{name}"%"替换成#{name},在传参的时候直接传"%李%"-->
<select id="getUserListLikeName" parameterType="String" resultType="User">
select * from user where name like "%"#{name}"%";
</select>
<!--增加用户-->
<insert id="addUser" parameterType="User">
insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd});
</insert>
<!--修改用户-->
<update id="updateUser" parameterType="User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id} ;
</update>
<!--万能的Map,修改用户-->
<update id="updateUserMap" parameterType="map">
update mybatis.user set pwd=#{userPwd} where id=#{userId} ;
</update>
<!--删除用户-->
<delete id="deleteUser" parameterType="_int">
delete from mybatis.user where id=#{id};
</delete>
</mapper>
id:里面的值是接口中的方法名
parameterType:传入的值。int代表Integer _int才代表int
parameterMap:作用和parameterType类似,好像是用于多参数。【未详细了解】
resultType:结果集,返回的结果为int时,resultType可以省略不写
MyTest测试
import com.kuang.dao.UserMapper;
import com.kuang.pojo.User;
import com.kuang.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MyTest {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.selectUser();
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userByIdList = mapper.getUserById(2);
for (User user : userByIdList) {
System.out.println(user);
}
}
@Test
public void getUserListLikeName(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserListLikeName("白");
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(8, "元宇宙", "dsadsad"));
}
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void updateUserMap(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map map = new HashMap<String, Object>();
map.put("userId",4);
map.put("userPwd","aileaile");
mapper.updateUserMap(map);
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(8);
}
@Test
public void deleteUser02(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(7);
}
}
resultMap
<!--结果集映射-->
<resultMap id="UserMap" type="user">
<!--colum数据库中的字段,property实体类中的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<!--解决数据库中字段和实体类中属性名不一致问题-->
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserList" resultMap="UserMap">
select * from mybatis.user;
</select>
分页
接口
//分页
List<User> getUserByLimit(Map<String,Integer> map);
Mapper.xml
<!--分页查询-->
<select id="getUserByLimit" parameterType="map" resultType="user">
select * from mybatis.user limit #{startIndex},#{pageSzie};
</select>
测试
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex",3);
map.put("pageSzie",2);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
多表查询
多对一处理
实体类
package com.kuang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String name;
//学生需要关联一个老师!
private Teacher teacher;
}
package com.kuang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private int id;
private String name;
}
接口
package com.kuang.dao;
import com.kuang.pojo.Student;
import java.util.List;
public interface StudentMapper {
List<Student> getStudent();
List<Student> getStudent2();
}
StudentMapper.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 namespace="com.kuang.dao.StudentMapper">
<!--按照查询嵌套处理-->
<select id="getStudent" resultMap="StudentTeacher">
select * from Student;
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from Teacher where id=#{id};
</select>
<!--按照结果嵌套处理-->
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.id tid,t.name tname
from student s,teacher t
where s.tid=t.id;
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
</mapper>
测试
@Test
public void StudentTeacher(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent();
for (Student student : studentList) {
System.out.println(student);
}
}
@Test
public void StudentTeacher2(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent2();
for (Student student : studentList) {
System.out.println(student);
}
}
一对多处理
实体类
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
//一个老师关联多个学生
private List<Student> students;
}
按照结果嵌套处理
<select id="getTeacher" resultMap="StudentByTeacher">
select s.id sid,s.name sname,t.id tid,t.name tname
from teacher t,student s
where t.id=s.tid and t.id = #{tid};
</select>
<resultMap id="StudentByTeacher" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--复杂的熟悉下那个,我们需要单独处理,对象:association 集合:collextion
javaType=""制定元素类型!
集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" ofType="Student">
<result column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
按照查询嵌套处理
<select id="getTeacher2" resultMap="StudentByTeacher2">
select * from mybatis.teacher where id = #{tid};
</select>
<resultMap id="StudentByTeacher2" type="Teacher">
<collection property="students" column="id" javaType="Arraylist" ofType="Student" select="getStudentbyTeacher" />
</resultMap>
<select id="getStudentbyTeacher" resultType="Student">
select * from mybatis.student where tid=#{tid};
</select>
小结
1.关联-association【多对一】
2.集合-collection【一对多】
3.javaType & ofType
1.javaType 用来制定实体类中属性的类型
2.ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型!
Mysql数据库搭建
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`name`,`pwd`)
values (1,'狂神','123456'),
(2,'张三','abcdef'),
(3,'李四','987654');
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (1, '小明', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, '小红', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, '小张', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, '小李', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, '小王', 1);
CREATE TABLE blog(
id varchar(50) not null comment '博客id',
title varchar(100) not null comment '博客标题',
author varchar(30) not null COMMENT '博客作者',
create_time datetime not null comment '创建时间',
views int(30) not null comment '浏览量'
)engine=innoDB default CHARSET=utf8
动态SQL
-if
-choose (when, otherwise)
-trim (where, set)
-foreach
注意:增删改方法的返回值是void或者Integer,用int会报错;
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
private int id;
private String title;
private String author;
private Date createTime;
private int views;
}
IF
<select id="queryBlogIF" 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>
choose(when,otherwise)
<select id="queryBlogChoose" 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>
trim(where,set)
<select id="queryBlogWhere" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<if test="title!=null">
and title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</where>
</select>
<update id="updataBlog" parameterType="map">
update blog
<set>
<if test="title!=null">
and title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</set>
where id=#{id};
</update>
SQL片段
1.使用SQL标签抽取公共的部分
<sql id="if-title-author">
<if test="title!=null">
and title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</sql>
2.在需要使用的地方使用Include标签引用即可
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<include refid="if-title-author"/>
</where>
</select>
注意事项:
- 最好基于单表来定义SQL片段!
- 不要存在where标签
Foreach
select * from user where 1=1 and
<foreach item='id' collection="ids"
open="and (" separetor="or" close=")">
#{id}
</foreach>
(id=1 or id=2 or id=3)
注意:and和(东西中间有个空格,否则where无法解析并去除第一个and
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确
一级缓存
- 一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段.
二级缓存
- 二级缓存也叫全局缓存,一级缓存的作用域太低了,所以诞生了二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
1.开启全局缓存
<settings>
<!--开启全局缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
2.再要使用二级缓存的Mapper中开启
<!--在当前Mapper.xml中使用二级缓存-->
<cache/>
也可以自定义参数
<!--在当前Mapper.xml中使用二级缓存-->
<cache eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
在标签中要添加 useCache="true"
<select id="queryUserBy" parameterType="_int" resultType="user" useCache="true">
select * from user where id=#{id};
</select>
测试
我们需要将实体类序列化!否则就会报错!
public class User implements Serializable {}
小结:
- 只要开启了二级缓存,在同一个Mapper下就有效
- 所有的数据都会先放在一级缓存中;
- 只有当会话提交,或者关闭的时候,才会提交到二级缓存中【转存】!
自定义缓存-ehcache
Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存
要在程序中使用ehcache,要先导包!
<!-- 自定义缓存 -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
在mapper中指定使用我们的ehcache缓存实现!
<!--在当前Mapper.xml中使用二级缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
创建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>