MyBatis与其使用方法讲解
ORM在讲解Mybatis之前,我们需了解一个概念ORM(Object-Relational Mapping)对象关系映射,其是数据库与Java对象进行映射的一个技术.通过使用ORM,我们可以不用编写负责的Sql语句,而是通过操作对象来实现增删改查操作
缺优分析
[*]优点
[*]提高开发效率,减少代码的重复性和维护成本
[*]增加代码的可读性,降低复杂度
[*]对数据库查询的细节进行抽象,隐藏了sql语句
[*]缺点
[*]在进行多表联查时,或存在where条件时,ORM语句会变得复杂
MyBatis
[*]mybatis是一个支持自定义SQL的持久层框架,通过XML文件来实现SQL配置和数据映射,MyBatis允许开发者手动编写SQL语句,提高灵活性
Mybatis通过mapper文件,将sql查询和Java对象绑定到一起,简化了JDBC代码的编写,手动设置参数,获取结果集的工作
MyBatis的工作流程
[*]其分为以下几步
MyBatis的基本使用
环境准备
[*]引入依赖包:
<!--springboot的mybatis ><dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version></dependency><!-- MySQL 连接器 --><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version></dependency>
[*]创建mybatis配置文件(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> <!-- mybatis环境 --> <environments default="mysql"> <environment id="mysql"> <!-- 配置事务的类型 --> <transactionManager type="JDBC"></transactionManager> <!-- 配置数据源(连接池) --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/数据库名称?userSSL=false&amp;serverTimezone=Asia/Shanghai"/> <property name="username" value="帐号"/> <property name="password" value="密码"/> </dataSource> </environment> </environments> <!-- mybatis映射配置位置 --> <!-- 按模块映射不同的配置文件,让配置文件看起来更简洁 --> <mappers> <mapper resource="映射配置文件全路径"></mapper> </mappers></configuration>
[*]springboot中的application.yml
mybatis:# mapper配置文件mapper-locations: classpath:mapper/*.xml# resultType别名,没有这个配置resultType包名要写全,配置后只要写类名type-aliases-package: com.mashang.xiaomistore.domainconfiguration: #下划线自动转驼峰 map-underscore-to-camel-case: true
[*]创建Mapper映射文件
<?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.company.mapper.StudentMapper"> <select id="queryAll" resultType="com.company.entity.Student"> SELECT * FROM student </select></mapper>
[*]创建Mapper接口:
public interface StudentMapper { List<Student> queryAll();}
MyBatis日志配置
[*]引入SpringBoot中的log4j
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j2 --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> <version>3.4.3</version></dependency>
[*]在SpringBoot中在application.yml中mybatis配置项中进行配置
mybatis:configuration: log-impl: org.apache.ibatis.logging.log4j.Log4jImpl
[*]配置log4j.properties文件
### 设置###log4j.rootLogger = debug,stdout,D,E### 输出信息到控制抬 ###log4j.appender.stdout = org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target = System.outlog4j.appender.stdout.layout = org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n### 输出DEBUG 级别以上的日志到=D://logs/error.log ###log4j.appender.D = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.D.File = D://logs/log.loglog4j.appender.D.Append = truelog4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}[ %t:%r ] - [ %p ]%m%n### 输出ERROR 级别以上的日志到=D://logs/error.log ###log4j.appender.E = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.E.File =D://logs/error.log log4j.appender.E.Append = truelog4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayoutlog4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}[ %t:%r ] - [ %p ]%m%n
[*]一个基本的mybatis的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.example.mapper.UserMapper"> <!-- CRUD 配置 --></mapper>
CURD实现
select查询
[*]使用<select>标签实现基本查询
<select id ="getUserById" resultType="com.company.domain.entity.User"> SELECT * FORM user </select>
[*]id:对应Mapper接口中的方法名,必须一致
[*]resultType:指定返回结果映射到哪个Java类
[*]传参#{}与${}的区别
[*]#{}的特点
[*]事先进行预编译:使用#{}的参数会被Mybatis当作JDBC中的?占位符
[*]防止sql注入:由于会事先进行预编译,Mybatis能够防止Sql注入
[*]类型转换:会根据参数类型进行适当的类型转换
[*]${}的特点
[*]字符串拼接:&{}直接将字符串进行替换,相当于在Sql中直接拼接传入的参数
[*]存在sql注入的风险:没有预编译,会引发sql注入问题
[*]多条件查询
<select id="getUserByNameAndAge" resultType="User"> SELECT * FROM user WHERE name = #{name} AND age = #{age}</select>
[*]模糊查询
<select> SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%')</select>
[*]使用LIKE关键字和CONCAT()函数进行查询
insert插入
[*]使用<insert>标签实现基本插入操作
<insert id="insertUser" parameterType="User"> INSERT INTO user(name, age) VALUES (#{name}, #{age}) </insert>
[*]parameterType:表示入参类型
[*]实现回填自增主键
[*]使用userGeneratedKeys和keyProperty实现
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> INSERT INTO user (name, age) VALUES (#{name}, #{age})</insert>
[*]userGeneratedKeys:表示是否启动自增
[*]keyProperty:表示将生成的主键赋值给哪个java对象的哪个属性如user.id
update更新
[*]使用<update>标签实现基本更新
<update id="updateUser" parameterType="User"> UPDATE user SET name=#{name}, age =#{age} WHERE id = #{id} </update>
delete删除
[*]使用<delete>标签基本查询
<delete id="deleteUserById" parameterType="Integer"> DELETE FROM user WHERE id = #{id} </delete>
传参方式
[*]多参数传参(使用@Param)
[*]当方法有多个参数时,使用@Param注解明确参数名
<select id="getUserByNameAndAge" resultType="User"> SELECT * FROM user WHERE name = #{name} AND age = #{age}</select>
[*]Mapper接口
User getUserByNameAndAge( @Param("name") String name, @Param("age") Integer age);
[*]对象参数
[*]当参数为一个Java对象时,MyBatis自动将对象属性映射到Sql语句中的占位符
<insert id="insertUser" parameterType="User"> INSERT INTO user (name, age) VALUES (#{name}, #{age})</insert>
[*]#{name}对应user.name,#{age}对应user.age
[*]Mapper接口
void insertUser(User user);
[*]Map参数
[*]通过Map传递多个参数或动态参数
<select id="getUserByMap" resultType="User"> SELECT * FROM user WHERE name = #{name} AND age = #{age}</select>
[*]Mapper接口
User getUserByMap(Map<String, Object> params);
[*]集合/数组参数
[*]适用于批量查询,比如WHERE id IN (…)
<select id="getUsersByIds" resultType="User"> SELECT * FROM user WHERE id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach></select>
[*]<foreach>是动态sql中的知识点等下会系统讲解
[*]Mapper接口
List<User> getUsersByIds(@Param("ids") List<Integer> ids);
动态sql
与标签
[*]<where>:生成WHERE子句,并自动判断去掉开头多余的AND/OR关键字,使sql更简洁
[*]<if>:用于判断传参条件,根据条件决定是否拼接某段SQL语句,适用于传参条件不固定,只有在满足条件时接入某个子串
<select id="getUserByCondition" resultType="User"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="age != null"> AND age = #{age} </if> </where></select>
[*]当name为非空,会添加AND name LIKE CONCAT('%', #{name}, '%') 当age为非空时会添加 AND age = #{age}
[*]结合标签使用,能自动处理首个AND,使得SQL语句正确
[*]其作用在于动态拼接SQL片段前添加或去除特点字符,比如前缀,后缀,以及多余的分隔符如,
[*]常用于INSERT和UPDATE语句,避免出现多余逗号
INSERT语句
<insert id="insertUserSelective" parameterType="User"> INSERT INTO user <trim prefix="(" suffix=")" suffixOverrides=","> <if test="name != null">name,</if> <if test="age != null">age,</if> <if test="email != null">email,</if> </trim> VALUES <trim prefix="(" suffix=")" suffixOverrides=","> <if test="name != null">#{name},</if> <if test="age != null">#{age},</if> <if test="email != null">#{email},</if> </trim></insert>
[*]标签包裹字段列表和对应值部分
[*]suffixOverrides=”,” 表示自动去除多余的逗号,确保sql语法正确
UPDATE语句
[*]<set>标签是<trim>的特性化
<update id="updateUserDynamic" parameterType="User"> UPDATE user <set> <if test="name != null">name = #{name},</if> <if test="age != null">age = #{age},</if> <if test="email != null">email = #{email},</if> </set> WHERE id = #{id}</update>
[*]<set>标签内部原理类似<trim>,会自动去除多余逗号
[*]<foreach>用于遍历集合,数组和Map,常用于批量操作或动态生成IN子句
[*]其主要属性
[*]collection:集合或数组名称(可用@Param()指定对应名称,默认为list或array)
[*]item:循环时每个元素的别名
[*]open:循环生成sql片段的前缀
[*]separator:循环时的分隔符
[*]close:循环生成sql片段的后缀
<select id="getUsersByIds" resultType="User"> SELECT * FROM user <where> <if test="ids != null"> AND id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </if> </where></select>
[*]当ids不为null时,进入<if test="ids != null">生成的sql片段为 SELECT * FROM ANDWHERE id IN(#{id},#{id},…)
[*]其中标签遍历集合ids,用逗号进行分隔,并在开头添加(括号,结尾添加)括号
[*]最终标签会去除第一个AND,使sql合法SELECT * FROM id WHERE IN(#{id},#{id},…)
MyBatis的映射
基本映射
用于单一的字段对应
[*]假设有一个user表,其中有字段id,name,age其在Java中有个简单的对应类User,其属性分别也是id,name,age那么在Mapper.xml进行select查询时
SELECT id, name, age FROM user WHERE id = #{id}
[*]MyBatis会将查询的结果中每一列值自动赋值给User对象中相同的属性
[*]数据库列表的id→User对象的id
[*]数据库列表的name→User对象的name
[*]数据库列表的age→User对象的age
[*]这样可能就会出现一种情况,数据库列表的列名与对象的属性名不一致,通常使用开启驼峰转换来解决→在application.yml的mybatis配置中添加如下配置:
mybatis: map-underscore-to-camel-case: true
一对一映射
当查询中需要查询一个对象时
[*]现假设,数据库有两张表一个user(用户)表,另一个user_detail(用户详细信息)表,在Java中我们可以创建两个类User和UserDetail类
[*]然后再创建一个UserVo类,其中包含User的属性和一个UserDatail对象
public class User { private Integer id; private String name; private Integer age;}public class UserDetail { private Integer detailId; private String address; private String phone;}public class UserVo { private Integer id; private String name; private Integer age; private UserDetail userDetail;// 一对一关系:一个用户对应一份详细信息 }XML配置如下:
<resultMap id="userVoMap" type="com.example.UserVo"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> <!-- 一对一映射 --> <association property="userDetail" javaType="com.example.UserDetail"> <id property="detailId" column="detail_id"/> <result property="address" column="address"/> <result property="phone" column="phone"/> </association></resultMap><select id="getUserVoById" resultMap="userVoMap" parameterType="int"> SELECT u.id, u.name, u.age, ud.detail_id, ud.address, ud.phone FROM user u LEFT JOIN user_detail ud ON u.id = ud.user_id WHERE u.id = #{id}</select>
[*]<resultMap>标签
[*]用于定义一组映射规则,将查询的结果转换为一个指定类型的Java对象
[*]属性
[*]id:为该映射指定一个唯一标识,供其在XML中引用使用,如<resultMap id="userResultMap" type="com.example.User">
[*]type:指定映射结果对应的Java类型(对象的全路径)
[*]<result>标签
[*]用于将数据库列映射到Java对象的属性,在<resultMap>中使用
[*]属性
[*]property:Java对象中的属性名称,如<result property="userName" column="user_name"/>其表示将查询到的user_name列的值赋值给userName属性
[*]cloumn:数据库查询结果中的列名,如column="user_name”表示sql查询列名为user_name的值
[*]<id>标签
[*]<id>类似于<result>主要用于映射主键字段
[*]属性
[*]property:与<result>相同,映射到Java对象的主键属性
[*]column:对应数据库中的主键列名
[*]<association>标签
[*]表示一个一对一关连
[*]当查询到结果时,MyBatis会将用户的基本字段{id,name,age}直接映射到UserVo中,同时将详细信息{detail_id,address,phone}封装为一个UserDetail对象,并赋值到UserVo的userDetail对象中
一对多映射
提供用于有列表对象的查询
[*]现假设一个老师(Teacher)类和一个学生(student)类,一个老师可以对应多个学生,在Java中我们可以设计Teacher类, 使用List属性来存放老师的所有学生
public class Teacher { private Integer id; private String teacherName; private Integer age; private List<Student> students; // 一对多关系:一个老师对应多个学生}public class Student { private Integer id; private String name; private Integer age;}XML配置如下:
<resultMap id="teacherMap" type="com.example.Teacher"> <id property="id" column="teacher_id"/> <result property="teacherName" column="teacher_name"/> <result property="age" column="teacher_age"/> <!-- 一对多映射 --> <collection property="students" ofType="com.example.Student"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> <result property="age" column="student_age"/> </collection></resultMap><select id="getTeacherWithStudents" resultMap="teacherMap" parameterType="int"> SELECT t.id as teacher_id, t.teacher_name, t.age as teacher_age, s.id as student_id, s.name as student_name, s.age as student_age FROM teacher t LEFT JOIN student s ON t.id = s.teacher_id WHERE t.id = #{id}</select>
[*]<collection>标签:用于表示一对多关系,把查询结果中的学生记录封装成一个列表,并赋值到Teacher对象中的student属性
页:
[1]