做网站前需要做什么准备互联网营销师是什么
MyBatis
持久层框架
MyBatis 是一个流行的 Java 持久层框架,专注于简化数据库操作。它通过 XML 或注解配置,支持自定义 SQL、存储过程和高级映射,极大地减少了繁琐的 JDBC 代码。MyBatis 的灵活性使其适用于需要精细控制 SQL 性能的场景,同时也能实现 SQL 与 Java 代码的分离,提升代码的可维护性
CRUD步骤
1.添加mybatis依赖
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.4</version></dependency>
2.创建java实体类
@Data
public class Emp {private Integer id;private String empName;private Integer age;private Double empSalary;
}
3.写Service接口,但此时是Mapper(加@Mapper注解)
@Mapper//告诉Spring,这是MyBatis操作数据库的Mapper接口
public interface EmpMapper {Emp getEmpById(Integer id);void addEmp(Emp emp);void deleteEmpById(Integer id);void updateEmp(Emp emp);List<Emp> getAllEmp();
}
4.为接口写xml文档,编写sql语句
5.调用接口方法即可
数据处理
#{}和${}
1. #{}
(PreparedStatement 方式,占位符)
特点
-
采用 预编译 方式,使用 JDBC
PreparedStatement
进行 SQL 传参。 -
防止 SQL 注入,因为参数是作为占位符传递,而不是直接拼接 SQL 语句。
-
性能较优,SQL 解析和执行效率较高。
2. ${}
(字符串替换方式)
特点
-
直接进行 字符串拼接,参数会被原样替换到 SQL 语句中。
-
容易引发 SQL 注入,因为参数值直接拼接到 SQL 语句里。
-
主要用于 动态 SQL(表名、列名) 需要动态拼接的场景。
<select id="getUserByColumn" resultType="User">SELECT * FROM user WHERE ${column} = #{value}
</select>编译的语句
SELECT * FROM user WHERE username = ?
多个参数时
@param注解可指定参数
`
编写sql语句时,若类的属性名和数据库的字段名不同,会导致数据无法赋值
解决方式
1.让属性名和字段名一样(不推荐)
2.编写sql语句时,给字段名起别名成属性名
3.在配置文件中声明驼峰命名转换mybatis.configuration.map-underscore-to-camel-case=true
4.在Mapperxml文件里写resultMap改名
<resultMap id="EmpRM" type="org.example.mybatis01helloworld.bean.Emp"><id column="id" property="id" /><result column="emp_name" property="empName" /><result column="age" property="age" /><result column="emp_salary" property="empSalary" /></resultMap>
最佳实践:
1.开启驼峰命名规则
2.1 搞不定的用自定义映射(resultMap)
关联查询
一对一的映射用association标签
<resultMap id="userResultMap" type="User"><id property="id" column="id"/><result property="name" column="name"/><association property="address" javaType="Address"><id property="id" column="address_id"/><result property="city" column="city"/></association>
</resultMap>
<select id="getUserWithAddress" resultMap="userResultMap">SELECT u.id, u.name, a.id as address_id, a.cityFROM users uLEFT JOIN addresses a ON u.address_id = a.idWHERE u.id = #{id}
</select>
一对多映射使用collection标签
<resultMap id="departmentResultMap" type="Department"><id property="id" column="id"/><result property="name" column="name"/><collection property="employees" ofType="Employee"><id property="id" column="employee_id"/><result property="name" column="employee_name"/></collection>
</resultMap>
<select id="getDepartmentWithEmployees" resultMap="departmentResultMap">SELECT d.id, d.name, e.id as employee_id, e.name as employee_nameFROM departments dLEFT JOIN employees e ON d.id = e.department_idWHERE d.id = #{id}
</select>
原生分布查询
编写多个sql语句,调用多次方法
自动分布查询
<resultMap id="DepartmentResultMap" type="Department"><id property="id" column="id"/><result property="name" column="name"/><!-- 一对多分步查询 --><collection property="employees" column="id"#传入的参数 select="getEmployeesByDeptId"#自动执行的sql语句 fetchType="lazy"/>
</resultMap>
<select id="getDepartmentById" resultMap="DepartmentResultMap">SELECT * FROM department WHERE id = #{id}
</select>
<select id="getEmployeesByDeptId" resultType="Employee">SELECT * FROM employee WHERE department_id = #{id}
</select>
要点: select属性写sql语句 column传入参数
动态sql
<if test=" ">判断是否执行
<select id="getUsers" resultType="User">SELECT * FROM userWHERE 1=1#防止逻辑错误<if test="name != null">AND name = #{name}</if><if test="age != null">AND age = #{age}</if>
</select>
where标签 解决where后面无条件或多and
set 标签 解决不传值时多逗号的情况
trim标签 可以代替where 和set 标签
-
prefix:指定需要添加的前缀,例如
WHERE
或SET
。 -
prefixOverrides:指定需要移除的前缀,比如
AND
、OR
。 -
suffix:指定需要添加的后缀。
-
suffixOverrides:指定需要移除的后缀。
choose/when/ortherwise 相当于switch(break)一旦找到配匹配的when就不会继续检查后面的when了
<select id="getUser" resultType="User">SELECT * FROM user<where><choose><when test="id != null">id = #{id}</when><when test="name != null">name = #{name}</when><otherwise>1=1</otherwise></choose></where>
</select>
foreach标签 collection 集合名
item 集合中的变量
separator 设置分隔符
open 指定开始的前缀
close 结束后缀
<select id="getUsersByIds" resultType="User">SELECT * FROM user WHERE id IN<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>
抽取可复用的sql片段
<sql id = "column_name">
xxxx
</sql>
缓存机制
两级缓存机制:
一级缓存机制
同一个 SqlSession
内 共享缓存,第一次查询数据库并缓存结果,第二次查询相同的sql时不访问数据库,直接从缓存取
二级缓存机制:
手动开启,在同一个mapper内,跨sqlsession共享
查找顺序:二一库
1.事务级别 默认开启
<!---同一个事务期间,前面查询的数据,后面如果要执行相同查询,会从一级缓存中获取数据-->
有时候缓存会失效:缓存不命中
-
查询的东西不一样
-
两次查询之间,进行了增删改(Mybatis会认为数据库发生了改变,所以要再发送一次查询)
2.所有事务共享 :需要手动配置开启
分页插件
1.手写limit语句
SELECT * FROM table_name LIMIT offset, pageSize;
offset
:跳过的记录数((pageNum - 1) * pageSize
)
pageSize
:每页显示的记录数
2.使用PageHelper插件
导入依赖
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.3.2</version>
</dependency>
service层
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo;
public PageInfo<User> getUsersByPage(int pageNum, int pageSize) {PageHelper.startPage(pageNum, pageSize); // 开启分页List<User> users = userMapper.getAllUsers(); // 查询所有return new PageInfo<>(users); // 封装分页信息
}
controller层实现
MybatisPlus
适合单表查询,多表查询还是自己编写更好
快速入门
导入依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.10.1</version>
</dependency>
在接口继承BaseMaper<T>
注入依赖.就可调用各种单表查询的方法
MybatisPlus通过扫描实体类,基于反射获取实体类信息作为数据库表信息
-
类名驼峰转下划线作为表名
-
名为id的字段作为主键
-
变量名驼峰转下划线作为表的字段名
常用注解
@TableName: 用来指定表名
@TableId: 用来指定表中的主键字段
@TableField: 用来指定表中的普通字段信息
成员变量名和数据库字段名不一致
成员变量名以is开头,且是布尔值
成员变量名和数据库关键字冲突
成员变量不是数据库字段@TableField(exist = false)
常见配置
核心功能
条件构造器Wrapper
基于QueryWrapper的查询
1.查询出名字中带o的,存款大于等于1000元的人的id,username,info,balance字段@Testpublic void testQueryWrapper(){//构建查询对象QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>().select("id", "username", "info", "balance").like("username", "o").gt("balance", 1000);//查询List<User> users = userMapper.selectList(userQueryWrapper);log.info("users = " + users);users.forEach(System.out::println);}
2.更新用户名为jack的用户工资 为2k@Testpublic void testUpdateByQueryWrapper(){User user = new User();user.setBalance(20000);QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "jack");userMapper.update(user,wrapper);}
基于UpdateWrapper的查询
1.把id为 1,2,4的用户工资减200@Testpublic void testReduceUserBalance(){List<Long> ids = List.of(1L, 2L, 4L);UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance-200").in("id",ids);userMapper.update(null,wrapper);}
使用lambdaQueryWrapper和LambdaUpdateWrapper
@Testpublic void testQueryWrapper(){//构建查询对象LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<User>().select(User::getId,User::getUsername,User::getInfo,User::getBalance).like(User::getUsername, "o").gt(User::getBalance, 1000);//查询List<User> users = userMapper.selectList(userQueryWrapper);users.forEach(System.out::println);}
自定义SQL
1.通过注解方式编写自定义sql
public interface UserMapper extends BaseMapper<User> {
@Select("SELECT * FROM user WHERE age > #{age}")List<User> selectByAge(int age);
}
@Select
注解可以用于执行 查询操作。
你也可以使用 @Insert
、@Update
、@Delete
注解来编写相应的操作 SQL。
利用mp构建复杂的where条件,然后剩下的sql语句自己写
IService接口
创建一个继承自IService的接口public interface IUserService extends IService<User> {void deductBalanceById(Long id, Integer money);//可自定义方法
}
创建接口的实现类,还要继承ServiceImpl<UserMapper,User>import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {// 通过继承 ServiceImpl,就不需要显式实现 CRUD 方法@Overridepublic User getUserByEmail(String email) {return baseMapper.selectOne(new QueryWrapper<User>().eq("email", email));}
}
实际开发中,使用IService接口更常见