创建Mybatis项目
MyBatis的写法
1.xml
2.注解
1.引入Mybatis依赖,引入对应数据库的依赖,比如mysql.
2.配置数据库相关信息
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
3.定义Java对象
package com.example.demo;
import java.util.Date;
public class UserInfo {
private Integer id ;
private String username;
private String password ;
private Integer age;
private Integer gender;
private String phono;
private Integer delete_flag;
private Date createTime ;
}
4.写实现
实现这里的@select注解是sql语句,其下面是对应方法声明。@Mapper注解, mybatis就会告诉Spring,把对象交给Spring管理。
package com.example.demo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.web.bind.annotation.Mapping;
import java.util.List;
@Mapper
public interface UserInfoMapper {
@Select("select * from userinfo")
List<UserInfo> selectAll();
}
在数据库中使用删除时分为:逻辑删除和物理删除
逻辑删除:指从逻辑上进行数据删除。物理删除:从硬盘上进行数据删除delete。二者的区分就是是否保存数据,现在数据非常宝贵,可以通过日常数据得知每个人的偏好和各种信息,所以现在一般都是采用逻辑删除来进行保存信息。
写测试类
右键生成中有测试直接选中
将这些都选中就会出现如下
@Slf4j//日志框架
@SpringBootTest//必需写上将Spring容器中的数据注入其中
class UserInfoMapperTest {
@Autowired
private UserInfoMapper userInfoMapper;
@BeforeEach//结果出现前打印
void setUp() {
log.info("setUP");
}
@AfterEach//结果出现后打印
void tearDown() {
log.info("setUP");
}
@Test
void selectAll(){
List<UserInfo> list =userInfoMapper.selectAll();
log.info(list.toString()) ;
}
}
在运行时,报这个错误时是有可能org.springframework.beans.factory.UnsatisfiedDependencyException
在启动类上面注解的后面加了(exclude = {DataSourceAutoConfiguration.class}),其意思是Spring Boot将不会自动配置数据源和JPA存储库相关的bean。
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
去掉之后正常运行
Mybaties的日志打印
mybatis:
configuration: #配置打印MyBatis日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
将会详细打印出数据库查询的运行轨迹
根据参数来进行查询结果
虽然如果只有一个参数,SQL的名称可以为任意的,但是还是将名称改为与其对应的,代码可读性高,以后也比较好进行修改。
@Select("select * from userinfo where id =#{id}")
UserInfo selectOne(Integer id);
//test
@Test
void selectOne() {
UserInfo userInfo = userInfoMapper.selectOne(1);
log.info(userInfo.toString());
}
查询结果
同时也可以将参数进行重命名来进行使用
@Select("select * from userinfo where id =#{userId}")
UserInfo selectOne2(@Param("userId") Integer id);
将参数进行重命名的目的是
- 语义化命名: 参数名
userId
更直观地表示了参数的含义,明确了该参数表示的是用户的 ID。 - 避免歧义: 当方法参数较多时,可能存在多个
id
参数,此时通过重命名可以避免歧义,明确是哪个参数代表用户的 ID。 - 可维护性: 如果后续需要修改参数名,只需要修改
@Param
注解中的值,而不需要修改 SQL 查询语句中的参数名,降低了修改的风险
插入数据
@Insert("insert into userinfo (username,password,age,gender,phone)"+
"values (#{username},#{password},#{age},#{gender},#{phone})")
Integer insert(UserInfo userInfo);
//test
@Test
void insert() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("sadada");
userInfo.setPassword("32324");
userInfo.setAge(2);
userInfo.setGender(1);
userInfo.setPhone("213123123");
Integer result = userInfoMapper.insert(userInfo);
log.info("insert",result);
}
结果
查询数据库中自增的数据
这个Op注解设置为true就是将自增数据的读取权限给打开,然后你就可以进行读取
sql语句太长换行加上”+“连进行连接
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into userinfo (username,password,age,gender,phone)"+
"values (#{username},#{password},#{age},#{gender},#{phone})")
Integer insert(UserInfo userInfo);
//test
@Test
void insert() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("ewqrwe");
userInfo.setPassword("ewrwe");
userInfo.setAge(1);
userInfo.setGender(1);
userInfo.setPhone("213123123");
Integer result = userInfoMapper.insert(userInfo);
log.info("insert,结果:{} ,自增ID:{}",result,userInfo.getId());//必修要使用{}才能捕获输出的值
}
不设置就会产生下面
参数为对象时,对参数进行重命名
并且重命名时,必修在参数前加上重命名的名称加上.否则不能进行识别,会报错
@Insert("insert into userinfo (username,password,age,gender,phone)"+
"values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender},#{userInfo.phone})")
Integer insert(@Param("userInfo") UserInfo userInfo);
删除数据
@Delete("delete from userinfo where id =#{id}")
Integer delete(Integer id);
@Test
void delete() {
UserInfo userInfo = new UserInfo();
Integer result = userInfoMapper.delete(16);
log.info("delete,{}",result);
}
更改数据
@Insert("insert into userinfo (username,password,age,gender,phone)"+
"values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender},#{userInfo.phone})")
Integer insert(@Param("userInfo") UserInfo userInfo);
//test
@Test
void update() {
UserInfo userInfo = new UserInfo();
userInfo.setAge(55);
userInfo.setId(10);
Integer result = userInfoMapper.update(userInfo);
log.info("update {}",result);
}
通过结果映射进行查询
结果映射
Mybatis 会自动的根据数据库的字段名和Java对象的属性名,进行映射如果名称一样.就讲行赋值
相同就进行了赋值,不同就置为空。
1.直接使用配置来进行自动转化
将createTime转化为create_time类型
mybatis:
configuration: #配置打印MyBatis日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true #配置驼峰自动转换
2.使用@Results注解
左边是数据库,右边是java对象的属性。并且其还能进行复用,在想复用的的方法上加上
@ResultMap(value = "BaseMap")
@Results(id= "BaseMap",value = {
@Result(column = "delete_flag",property = "deleteFlag")
})
@Select("select * from userinfo")
List<UserInfo> selectAll2();
//复用
@ResultMap(value ="BaseMap")
@Select("select * from userinfo;")
List<UserInfo> selectAll();
XML方式
1.先配置数据库
2.指明xml的路径
mybatis:
# configuration: #配置打印MyBatis日志
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# map-underscore-to-camel-case: true #配置驼峰自动转换
mapper-locations:
classpath:mapper/**Mapper.xml
classpath后面对应的是Mapper.xml放在哪里并且Mapper.xml这个文件前面是什么无所谓,只要后面这几个是Mapper.xml就可以。
3.写XML的实现
namespace后面写的要实现哪个接口以及要写接口的全限定类名。id写的是实现的方法名,resultType则是返回的类型,返回的是对象,或者list, 此处定义的都是返回的数据的类型
<?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.demo.mapper.UserInfoXMLMapper">
<select id="selectALL" resultType="com.example.demo.UserInfo">
select * from userinfo
</select>
</mapper>
//所在的类的方法
@Mapper
public interface UserInfoXMLMapper {
List<UserInfo> selectALL();
}
如果下面报错
Invalid bound statement (not found):com.bite.demo.mapper.UserInfoXNLNapper.selectAll
可能原因
1.xml和接口定义的方法名称不一致 2.mapper的路径配置和xml的路径不一样 3.xml namespace写错了
曾删改和注解类似
Integer insert(UserInfo userInfo);
//XML
<insert id="insert">
insert into userinfo (username,password,age,gender,phone)
values(#{username},#{password},#{age},#{gender},#{phone})
</insert>
//test
@Test
void insert() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("ewqrwe");
userInfo.setPassword("ewrwe");
userInfo.setAge(1);
userInfo.setGender(1);
userInfo.setPhone("213123123");
Integer result = userInfoXMLMapper.insert(userInfo);
log.info("result ,{}",result);
}
Integer insert2(@Param("userInfo") UserInfo userInfo);
//XML
<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
iinsert into userinfo (username,password,age,gender,phone)
values(#{userInfo.username},#{userInfo.password}
,#{userInfo.age},#{userInfo.gender},#{userInfo.phone})
</insert>
//test
@Test
void insert2() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("ewqrwe");
userInfo.setPassword("ewrwe");
userInfo.setAge(1);
userInfo.setGender(1);
userInfo.setPhone("213123123");
Integer result = userInfoXMLMapper.insert(userInfo);
log.info("result ,{}",result);
}
Integer delete(Integer id);
//XML
<delete id="delete">
delete from userinfo where id =#{id}
</delete>
//test
@Test
void delete() {
UserInfo userInfo = new UserInfo();
Integer result = userInfoXMLMapper.delete(11);
log.info("delete,{}",result);
}
Integer update(UserInfo userInfo);
//Xml
<update id="update">
update userinfo set gender =#{gender}
where id =#{id}
</update>
//test
@Test
void update() {
UserInfo userInfo = new UserInfo();
userInfo.setGender(2);
userInfo.setId(2);
Integer result = userInfoXMLMapper.update(userInfo);
log.info("update,{}",result);
}
动态SQL的使用:根据需求,动态的拼接sql
XML方式的明显可读性很高
如果性别不为空不为空都不可读,if就是用来判断的条件
//注解方式
@Insert("<script>" +
"INSERT INTO userinfo (username,`password`,age," +
"<if test='gender!=null'>gender,</if>" +
"phone)" +
"VALUES(#{username},#{age}," +
"<if test='gender!=null'>#{gender},</if>" +
"#{phone})"+
"</script>")
Integer insert2(UserInfo userInfo);
//XML
<insert id="insert3">
INSERT INTO userinfo (
username,
`password`,
age,
<if test="gender != null">
gender,
</if>
phone)
VALUES (
#{username},
#{age},
<if test="gender != null">
#{gender}
</if>
#{phone})
</insert>
<trim>标签帮助我们去除多余的字符
<trim>
prefix0verrides去除trim标签代码块指定的字符
prefix在trim标签代码块最前面添加指定的字符
suffix在trim标签代码块最后面添加指定的字符
suffix0verrides去除trim标签代码块最后面指定的字符
示例
<trim suffixOverrides="," prefix="(" suffix=")">
<if test="username!=null">
username,
</if>
<if test="password!=null">
password,
</if>
<if test="age!=null">
age,
</if>
<if test="gender!=null">
gender,
</if>
<if test="phone!=null">
phone
</if>
</trim>
XML中的插入
<insert id="insert3">
INSERT INTO userinfo
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username !=null">
username,
</if>
<if test="password !=null">
`password`,
</if>
<if test="age!=null">
age,
</if>
<if test="gender !=null">
gender,
</if>
<if test="phone!=null">
phone,
</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username!=null">
#{username},
</if>
<if test="password!=null">
#{password},
</if>
<if test="age!=null">
#{age},
</if>
<if test="gender!=null">
#{gender},
</if>
<if test="phone!=null">
#{phone}
</if>
</trim>
</insert>
基于prefix配置,开始部分加上( 。
基于suffix配置,结束部分加上)
多个组织的语句都以,结尾,在最后拼接好的字符串还会以,结尾,会基于suffixOverrides配置去掉最后一个,
注意<if test="username !=null">中的username是传入对象的属性
<where>标签
如果查询条件都为空, where标签会自动去除where关键
<select id="selectAll" resultType="com.example.demo.model.UserInfo">
select id, username, age, gender, phone, delete_flag, create_time,
update_time
from userinfo
<where>
<if test="age != null">
and age = #{age}
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="deleteFlag != null">
and delete_flag = #{deleteFlag}
</if>
</where>
</select>
where标签只会在⼦元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的AND或 OR
<set>标签
<update id="update">
update userinfo
<set>
<if test="username != null">
username = #{username},
</if>
<if test="age != null">
age = #{age},
</if>
<if test="deleteFlag != null">
delete_flag = #{deleteFlag},
</if>
</set>
where id = #{id}
</update>
set标签动态的在SQL语句中插⼊set关键字,并会删掉额外的逗号.
<foreach>标签的属性
collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
item:遍历时的每⼀个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
用于多个userid, 删除⽤⼾数据,类似于循环使用数组中的每一个元素
<delete id="deleteByIds">
delete from userinfo
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<include>标签
使用一些重复的sql时,使用<include>标签来进行重复使用
//可以重复使用的
<sql id="allColumn">
id, username, age, gender, phone, delete_flag, create_time, update_time
</sql>
//include标签
<select id="queryAllUser" resultMap="BaseMap">
select
<include refid="allColumn"></include>
from userinfo
</select>
<select id="queryById" resultType="com.example.demo.model.UserInfo">
select
<include refid="allColumn"></include>
from userinfo where id= #{id}
</select>