Mybatis
是一款优秀的持久层框架,它支持定制化 SQL
避免了几乎所有的 JDBC 代码和手动设置参数
导入jar
包
<!--mybatis依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--jdbc依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok的包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
数据映射
pojo: 程序通过对象封装数据信息
一个pojo对象要求映射一张数据表
对象名称 映射数据表表名
对象的属性 映射数据表中的字段
也就是说 数据库里面的一个表对应Java
里面的一个对象
类似于如下
@Data // 添加 get set方法
@Accessors(chain = true) // 重写set方法
@NoArgsConstructor// 无参构造
@AllArgsConstructor// 全参构造
// 实现 序列化接口
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private String sex;
}
在resources
目录里创建mybatis-config.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">
<!-- mybatis中采用 jdbc的事务控制-->
<transactionManager type="JDBC"/>
<!-- jdbc连接 池-->
<dataSource type="POOLED">
<!--使用高版本的驱动-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--数据库的地址-->
<property name="url" value="jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true"/>
<!-- 用户名 和密码 -->
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--Mybatis加载Mapper映射文件-->
<!--添加对应的映射文件路径-->
<mappers>
<!--这里的路径一定要匹配上 -->
<mapper resource="mappers/userMapper.xml"/>
</mappers>
</configuration>
编辑映射文件
将对象和数据库里的表对应起来
配置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">
<!--namespace是mybaits映射文件的唯一标识,与接口对应-->
<!--写的是 包路径-->
<mapper namespace="com.jt.mapper.UserMapper">
<!-- 和 接口里的方法名 对应 -->
<!-- 执行 插入数据操作 使用insert标签 <insert id=""></insert>-->
<!-- 执行 修改操作 <update id=""></update>-->
<!--id 表示接口方法
resultType 返回值结果类型 对象
-->
<select id="findAll" resultType="com.jt.pojo.User">
select * from demo_user
</select>
</mapper>
使用
public void testDemo1() throws IOException {
// 指定配置文件的根目录
String resource = "mybatis-config.xml";
// 通过IO流 加载配置文件
// 通过流文件 读取里面创建了几个 映射
InputStream inputStream = Resources.getResourceAsStream(resource);
// builder 建造者模式
// 实例化 工厂对象
// SqlSessionFactory 目的是获取 SqlSession
// SqlSession 包装了 数据库的连接 和 连接器对象
// 通过SqlSession 可以直接连接数据库
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 打开数据库连接
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取接口对象
UserMapper userMapper = sqlSession.getMapper(userMapper.class);
// 完成业务调用
List<user> userList = userMapper.findAll();
System.out.println(userList);
//关闭连接
sqlSession.close();
}
方法2
由于Mybatis
依赖了JDBC
的包 但是该包文件是启动项,
当主启动项开始加载启动项
但是JDBC
需要连接数据库所以必须有配置相关的信息
配置resources
文件夹里的application.yml
文件
# 配置端口
server:
port: 8090
# 配置数据源
# driver-class-name 包文件 cj.jdbc 是高版本的
# url 数据库的地址
# username 数据库的用户名
# password 数据库的密码 密码开头是0的需要使用引号包裹 如 "01234"
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
# type-aliases-package pojo包路径
mybatis:
type-aliases-package: com.jt.pojo
# mapper-locations xml的配置文件存放路径
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
Mapper
层增加注解
@Mapper // 将接口交给 spring 管理容器进行管理 存储的是Map<UserMapper,JDK代理对象>
public interface UserMapper {
// 查询 demo_user的全部数据
List<User> findAll();
}
使用
@Test
public void testDemo(){
List<User> userList = userMapper.findAll();
System.out.println(userList);
}
MyBatis的增删改查
xml
文件里的配置
<!-- 根据id查询用户
findUserById 是方法名
resultType 是返回值 此写法是返回User对象
-->
<select id="findUserById" resultType="com.jt.pojo.User">
select * from demo_user where id=#{id}
</select>
使用
@Mapper // 将接口交给 spring 管理容器进行管理 存储的是Map<UserMapper,JDK代理对象>
public interface UserMapper {
// 根据id查询数据库
User findUserById(int id);
}
@Autowired
private UserMapper userMapper;
@Test
public void testFindUserById(){
User user = userMapper.findUserById(1);
System.out.println(user);
}
打印 sql日志
# 打印 sql
# 打印com.jt.mapper 的sql日志
logging:
level:
com.jt.mapper: debug
如果多个参数需要进行传递一般采用对象的方式封装
如:
User user = new User();
user.setName("白龙驴");
user.setAge(200);
List<User> userList = userMapper.findUserByNA(user);
多个数据查询
<!-- 参数传递的规则
如果是 单个 参数则使用 #{key}
如果是 对象 参数则使用 #{属性}
-->
<select id="findUserByNA" resultType="User">
select * from demo_user where name=#{name} and age=#{age}
</select>
如果多个参数不方便封装
使用万能集合Map
int minAge = 18;
int maxAge = 200;
HashMap<String, Integer> map = new HashMap<>();
map.put("minAge", minAge);
map.put("maxAge", maxAge);
List<User> userList = userMapper.findUserByAge(map);
或者可以使用多个值
但是在Mapper
里面使用注解@Param
如:
@Mapper // 将接口交给 spring 管理容器进行管理
public interface UserMapper {
// 原则上 支持单值 传参 多值封装成 单值
// 原理是将多个值自动封装成 Map 集合
List<User> findUserByAge2(@Param("minAge") int minAge,@Param("maxAge") int maxAge);
}
查询范围的值
<!--特殊转义字符
> >
< <
& &
万能转义标签 <![CDATA[ 需要转义的内容 ]]>
万能转义 需要把 sql 语句 整体写入里面 如:
<![CDATA[ select * from demo_user where age > #{minAge} and age < #{maxAge} ]]>
-->
<select id="findUserByAge" resultType="User">
select * from demo_user where age > #{minAge} and age < #{maxAge}
</select>
模糊查询
<select id="findUserByLike" resultType="User">
<![CDATA[
select * from demo_user where name like #{name}
]]>
</select>
String name = "%" + "李" + "%";
List<User> userList = userMapper.findUserByLike(name);
System.out.println(userList);
sql标签
sql语句中经常出现重复的数据如果每次
重复的内容都手写则开发效率低
使用sql标签进行抽取
<!-- sql标签 抽取公共的sql语句 -->
<sql id="tableColumn">
select * from demo_user
</sql>
使用sql标签
<select id="findUserByNA" resultType="User">
<include refid="tableColumn"/>
where name=#{name} and age=#{age}
</select>
mybatis的循环
foreach 遍历标签
collection 需要遍历的集合
-
数组 关键字 array
-
list集合 关键字 list
-
ap<key,arr/list>
关键字 keyopen/close 循环的开始结束符
item 当前遍历数据的 变量
separator 表示分隔符
<select id="findById" resultType="User">
select * from demo_user where id in
<foreach collection="array" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
新增删除操作基本相同
新增
<insert id="saveUser">
insert into demo_user(name,age,sex)
values(#{name},#{age},#{sex})
</insert>
新增操作默认是有返回值 int
类型
可以不接收
动态sql
根据传过来的对象中的属性不为空(null) 当做属性
<!-- where标签用来去除 多余的一个 and/or -->
<!-- if 判断属性如果不为空则查询 -->
<select id="findUserList" resultType="User">
select * from demo_user
<where>
<if test="id !=null">id = #{id}</if>
<if test="name !=null">and name = #{name}</if>
<if test="age !=null">and age = #{age}</if>
<if test="sex !=null">and sex = #{sex}</if>
</where>
</select>
动态的更新
<!--去除if 里面最后一个逗号-->
<update id="updateUser">
update demo_user
<set>
<if test="name !=null">name = #{name},</if>
<if test="age !=null">age = #{age},</if>
<if test="sex !=null">sex = #{sex}</if>
</set>
where id = #{id}
</update>
sql分支语句
如果不满足某个条件
则使用另一个条件
<!-- 相当于 swatch catch
choose 是开启判断
when 是否满足 test 里的判断
如果是 查询里面的语句 不满足 跳过 往下执行
是否有下一个 when 如果上方的条件都没有满足执行 otherwise 相当于 default
-->
<select id="findUserByNS" resultType="User">
select * from demo_user
<where>
<choose>
<when test="name !=null">
name = #{name}
</when>
<otherwise>
sex = #{sex}
</otherwise>
</choose>
</where>
</select>
表字段与对象属性不一致
关于映射文件的返回值resultType
只能支持
数据库的表 字段名称 与 属性名称 一致才能自动映射
<select id="findAll" resultType="Dog">
select * from dog
</select>
不满足时
使用resultMap
<select id="findAll" resultMap="dogRM">
select * from dog
</select>
<!--自己封装 映射关系-->
<resultMap id="dogRM" type="Dog">
<!-- ID代表主键
-->
<id column="dog_id" property="dogId"></id>
<!-- 结果集 -->
<result column="dog_name" property="dogName"></result>
<!-- 属性名 与表名一致时 可以不用封装 -->
</resultMap>
配置文件中的驼峰映射
如果经常出现
数据库表字段user_id
Java属性userId
两者是驼峰映射关系
可以在application.yml
文件里配置如下
开启了驼峰映射规则
mybatis:
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
关联关系
表与表之间的关联如
一个老师对应多个学生
一个学生对应多个老师
封装pojo
文件时对应关联关系
如: 一个员工对应一个部门
public class Emp implements Serializable {
private Integer id;
private String name;
private Integer age;
//一个员工对应一个部门
private Dept dept;
}
xml
文件写法
resultMap
标签使用assoction
标签
<!--
如果操作的是 单标 使用resultType
如果进行的是 关联 使用resultMap
如果是多表进行关联 结果集不允许出现重名字段
-->
<select id="findAll" resultMap="empMap">
SELECT e.id,e.name,e.age,e.dept_id,d.dept_name FROM emp e LEFT JOIN dept d ON e.dept_id=d.dept_id;
</select>
<!-- 没有关联映射时 对象里的属性 和 数据库表里的字段 同名可以不写 -->
<!-- 如果有关联映射时 添加自动映射的开关 autoMapping -->
<!-- autoMapping 只对添加的当前对象有效 如果有多个对象 添加多次 -->
<resultMap id="empMap" type="Emp" autoMapping="true">
<!--主键 必须写-->
<id column="id" property="id"/>
<!--
一对一关联封装 使用 association
property 指对象里的属性 dept属性
必须指定属性的类型 javaType 属性 封装的对象
-->
<!-- 添加自动映射的开关 autoMapping="true" -->
<association property="dept" javaType="Dept" autoMapping="true">
<!-- Dept的主键 -->
<id column="dept_id" property="deptId"/>
</association>
</resultMap>
一对多关联
如: 一个部门对应多个员工
public class Dept implements Serializable {
private Integer deptId;
private String deptName;
// 一个部门对应多个员工
private List<Emp> emps;//使用集合封装
}
xml
文件配置
resulMap
标签里使用collection
标签
<resultMap id="deptRM" type="Dept" autoMapping="true">
<id property="deptId" column="dept_id"/>
<!-- 一对多封装 collection -->
<!--
property 对象里的属性
ofType 封装的对应对象
-->
<collection property="emps" ofType="Emp" autoMapping="true">
<id property="id" column="id"/>
</collection>
</resultMap>
注解sql
利用注解自动映射
注解和映射文件 二选一
@Mapper
public interface UserAnnoMapper {
@Select("select * from demo_user")
List<User> findAll();
}
使用参数
@Mapper
public interface UserAnnoMapper {
@Select("select * from demo_user")
List<User> findAll();
@Select("select * from demo_user where id=#{id}")
User findUserById(int id);
}
查询注解@Select
插入注解@Insert
更新注解@Update
删除注解@Delete
MyBatis缓存
MyBatis中提供了两种缓存机制
一级缓存: 在同一个sqlSession
内实现数据共享
一个人多次查询同一个sql 默认开启
二级缓存: 在同一个sqlSessionFactory
生产的sqlSession
数据共享
并发操作 默认开启
一级缓存@Transactional
如果采用 springboot 的方式测试 一级缓存无效
因为 springboot 整合mybatis 使用查询时 springBoot会开启多个 sqlSession
创建了多个 sqlSession
对象
需要添加@Transactional
@Test
@Transactional // 控制事务
public void testCache1(){
List<User> userList = userAnnoMapper.findCache1();
List<User> userList1 = userAnnoMapper.findCache1();
List<User> userList2 = userAnnoMapper.findCache1();
List<User> userList3 = userAnnoMapper.findCache1();
List<User> userList4 = userAnnoMapper.findCache1();
}
开启二级缓存
二级缓存springboot 默认开启
但是需要一些配置xml
文件里面增加一个标签
<mapper namespace="com.jt.mapper.UserAnnoMapper">
<!--
开启二级缓存
pojo 里面的对象必须实现 序列化 Serializable
-->
<cache/>
<select id="findCache1" resultType="User">
select * from demo_user
</select>
</mapper>
pojo
里的对象必须实现 序列化serializable
// 序列化接口 Serializable
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private String sex;
}
注解开启二级缓存
在mapper里使用注解@CacheNamespace
@Mapper
@CacheNamespace
public interface UserAnnoMapper {
@Select("select * from demo_user")
List<User> findAll();
}
如果使用注解则
xml
文件里面不能使用<cache/>
标签