拓冰建站拓冰建站
首页 / 资讯中心 / 正文

MyBatis增删改查与参数处理:从流程复用到安全查询实战

第一部分流程复用思路1.1 核心思想⭐老师强调首个流程走通后后续流程无需重复写前期逻辑因为基础已铺垫好只需编写并调用核心业务段即可。流程复用示例流程需要写的代码第一个流程findAll完整写加载配置、创建工厂、会话、映射、查询、处理结果后续流程findById、insert等只写接口方法 映射文件 测试调用⭐老师强调区分写逻辑和调业务——第一个流程要完整写查找等逻辑后续只管写核心段、调核心业务不必重铺前文。第二部分增删改查完整实现2.1 接口定义StudentDao.javapackage com.qcby.dao; import com.qcby.entity.Person; import com.qcby.entity.Student; import org.apache.ibatis.annotations.Param; import java.util.List; public interface StudentDao { // 查找全部学生信息 ListStudent findAll(); // 根据id查找学生信息 Student findById(int id); // 插入 int insert(Student student); // 删除 int delete(int id); // 修改 int update(Student student); // 模糊查找 ListStudent findByName(String name); // 分页查找 ListStudent findStudent(Param(name123) String name, Param(start) int start, Param(limit) int limit); // 包装对象参数 ListStudent findAllPerson(Person person); }2.2 映射文件StudentDao.xml?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.qcby.dao.StudentDao !-- 查找全部使用resultMap映射 -- select idfindAll resultMapdemo select * from student /select resultMap iddemo typecom.qcby.entity.Student result columnid propertyid jdbcTypeINTEGER javaTypejava.lang.Integer/ result columnsname propertyname jdbcTypeVARCHAR javaTypejava.lang.String/ result columnsage propertyage/ result columnsex propertysex/ /resultMap !-- 根据id查找 -- select idfindById parameterTypejava.lang.Integer resultTypecom.qcby.entity.Student select * from student where id #{id} /select !-- 插入带selectKey获取自增id -- insert idinsert parameterTypecom.qcby.entity.Student insert into student(name,age,sex) values(#{name},#{age},#{sex}) selectKey keyPropertyid keyColumnid resultTypejava.lang.Integer orderAFTER select last_insert_id() /selectKey /insert !-- 删除 -- delete iddelete parameterTypecom.qcby.entity.Student delete from student where id #{id} /delete !-- 修改 -- update idupdate parameterTypecom.qcby.entity.Student update student set name #{name},age#{age},sex#{sex} where id #{id} /update !-- 模糊查找推荐用concat -- select idfindByName parameterTypejava.lang.String resultTypecom.qcby.entity.Student select * from student where name like concat(%,#{name},%) /select !-- 分页查找多参数用Param注入 -- select idfindStudent resultTypecom.qcby.entity.Student select * from student where name like concat(%,#{name123},%) limit #{start},#{limit} /select !-- 包装类对象参数 -- select idfindAllPerson parameterTypecom.qcby.entity.Person resultTypecom.qcby.entity.Student select * from student where age #{student.age} /select /mapper第三部分#{}与${}的区别3.1 核心对比对比#{}${}本质占位符赋值预编译字符串拼接防SQL注入✅ 能❌ 不能简单类型变量名任意写低版本必须value高版本任意写字符串字段自动加不会自动加实体类对象必须是引用类型的属性必须是引用类型的属性⭐老师强调#{}本质同JDBC预编译占位符把用户输入与指令分离能挡SQL注入${}是纯拼接先拼成完整SQL再编译执行你传什么就拼什么去查。3.2 示例说明!-- #{}预编译占位安全 -- select idfindById parameterTypejava.lang.Integer resultTypecom.qcby.entity.Student select * from student where id #{id} /select !-- ${}字符串拼接有注入风险 -- select idfindByName parameterTypejava.lang.String resultTypecom.qcby.entity.Student select * from student where name like %${name}% /select !-- ✅ 推荐concat #{}既安全又能模糊查询 -- select idfindByName parameterTypejava.lang.String resultTypecom.qcby.entity.Student select * from student where name like concat(%,#{name},%) /select⭐老师强调#{}写在SQL引号内无法将参数塞入占位符必须写在引号外。涉及引号时框架会自动加引号。3.3 字符串字段的引号处理!-- ${}不会自动加引号字符串字段必须手动加 -- insert into student(name,age,sex) values(${name},${age},${sex}) !-- #{}会自动加引号无需手动处理 -- insert into student(name,age,sex) values(#{name},#{age},#{sex})第四部分参数类型详解4.1 四种入参类型⭐老师强调parameterType入参类型分四类。类型说明示例简单数据类型8个基本类型包装类Stringjava.lang.Integer、java.lang.String实体类对象类型整个对象作为参数com.qcby.entity.Student多个数据多个参数用Param注入Param(name) String name, Param(start) int start包装对象类型实体类嵌套实体类com.qcby.entity.Person内含Student4.2 简单类型select idfindById parameterTypejava.lang.Integer resultTypecom.qcby.entity.Student select * from student where id #{id} /select⭐老师强调简单类型参数括号里变量名可任意写都能识别。推荐写全称如java.lang.Integer更规范。String本质是引用类型但因太常用传参时和int无区别。4.3 实体类对象类型insert idinsert parameterTypecom.qcby.entity.Student insert into student(name,age,sex) values(#{name},#{age},#{sex}) /insert⭐老师强调括号里的名字必须与实体类字段名严格匹配随便写demo这类不存在的字段就识别不到。传入的是对象就得按对象结构取属性。4.4 多个参数Param注入// 接口 ListStudent findStudent(Param(name123) String name, Param(start) int start, Param(limit) int limit);!-- 映射文件 -- select idfindStudent resultTypecom.qcby.entity.Student select * from student where name like concat(%,#{name123},%) limit #{start},#{limit} /select⭐老师强调多参数时#{}无法直接绑定必须用Param注解注入——注解里写什么名#{}里就用什么名。多个参数写法直接写在方法括号中即可。4.5 包装对象类型实体类嵌套Person实体类package com.qcby.entity; public class Person { private Student student; public Student getStudent() { return student; } public void setStudent(Student student) { this.student student; } Override public String toString() { return Person{student student }; } }映射文件select idfindAllPerson parameterTypecom.qcby.entity.Person resultTypecom.qcby.entity.Student select * from student where age #{student.age} /select测试代码Test public void findAllPerson() { Person person new Person(); Student student new Student(); student.setAge(25); student.setName(小宇); student.setSex(男); student.setId(28); person.setStudent(student); ListStudent students mapper.findAllPerson(person); for (Student s : students) { System.out.println(s); } }⭐老师强调当入参是包含嵌套类型的实体类如Person里嵌了Student若想用Student里的字段做条件直接用点形式访问即可如#{student.age}。难点在于理解嵌套对象字段的访问路径——不像平铺字段直接取得明确层级。第五部分resultMap结果集映射5.1 为什么需要resultMap⭐老师强调当数据库字段和实体属性名称不匹配如库里是sname/sage代码里是name/age时不能用resultType必须改用resultMap做结果集映射。5.2 使用方式resultMap iddemo typecom.qcby.entity.Student !-- column: 数据库中的字段名称 -- !-- property: 实体类中的名字 -- !-- jdbcType: 数据库中的字段类型 -- !-- javaType: 实体类中数据的类型 -- result columnid propertyid jdbcTypeINTEGER javaTypejava.lang.Integer/ result columnsname propertyname jdbcTypeVARCHAR javaTypejava.lang.String/ result columnsage propertyage/ result columnsex propertysex/ /resultMap select idfindAll resultMapdemo select * from student /select5.3 属性说明属性说明是否必须column数据库字段名✅ 必须property实体类属性名✅ 必须jdbcType数据库字段类型大写❌ 可省略javaType实体类数据类型❌ 可省略⭐老师强调jdbcType和javaType不写也能自动识别写了反而容易出错所以尽量别写。column和property是映射核心不能省。第六部分插入后获取自增id6.1 selectKey的使用insert idinsert parameterTypecom.qcby.entity.Student insert into student(name,age,sex) values(#{name},#{age},#{sex}) selectKey keyPropertyid keyColumnid resultTypejava.lang.Integer orderAFTER select last_insert_id() /selectKey /insert6.2 属性说明属性说明keyProperty把查出的主键放到哪个属性如Student的idkeyColumn数据库主键名如idresultType主键类型orderAFTER插入后查BEFORE插入前查⭐老师强调order的区分设了自动递增用AFTER插入后自动把新id返到对象里没设自动递增用BEFORE添加前先查id为什么不查max(id)单线程下查最大id可行但并发场景下你插入完、查最大id前可能别的线程也插了数据。必须用返回刚插入id的机制才可靠6.3 测试代码Test public void insert() { Student student new Student(); student.setName(小红); student.setAge(18); student.setSex(女); int code mapper.insert(student); // 事务提交 session.commit(); System.out.println(code); // 受影响行数 System.out.println(student.getId()); // 刚插入的id System.out.println(student); }⭐老师强调执行后返回两样一是受影响行数二是最新添加记录的id直接存入Student对象不单独返回。第七部分事务提交7.1 何时需要事务提交操作是否需要commit增删改✅ 必须查询❌ 不需要⭐老师强调只有增删改这类改动数据库的操作才需要事务提交查找不用。不加事务提交数据无法真正写入库里。7.2 测试示例Test public void delete() { int code mapper.delete(26); session.commit(); // 必须提交 System.out.println(code); } Test public void update() { Student student new Student(); student.setName(小宇); student.setAge(20); student.setSex(男); student.setId(28); int code mapper.update(student); session.commit(); // 必须提交 System.out.println(code); }⭐老师强调修改操作时name、age、sex三个参数必须全传少一个就会出错后续可加动态SQL来避免这个问题。第八部分日志配置8.1 settings配置configuration settings setting namelogImpl valueSTDOUT_LOGGING/ /settings environments defaultmysql ... /environments mappers ... /mappers /configuration⭐老师强调MyBatis配置文件有严格的标签顺序约束——settings必须最前接着是environments最后是mappers。乱序会报错。8.2 日志效果配置后可以看到SQL执行全过程 Preparing: select * from student where id ? Parameters: 10(Integer) Columns: id, sname, sage, sex⭐老师强调日志体现预编译防注入机制——先有?占位符再传入值塞进占位处。第九部分测试类完整代码package com.qcby; import com.qcby.dao.StudentDao; import com.qcby.entity.Person; import com.qcby.entity.Student; 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 org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class StudentTest { private InputStream inputStream null; private SqlSession session null; private StudentDao mapper null; Before // 前置通知 public void init() throws IOException { // 加载主配置文件 inputStream Resources.getResourceAsStream(SqlMapConfig.xml); // 创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream); // 创建SqlSession对象 session sqlSessionFactory.openSession(); // 通过sqlsession创建接口的代理对象 mapper session.getMapper(StudentDao.class); } After public void destroy() throws IOException { session.close(); inputStream.close(); } Test public void run() { ListStudent students mapper.findAll(); for (Student student : students) { System.out.println(student); } } Test public void findById() { Student student mapper.findById(10); System.out.println(student); } Test public void insert() { Student student new Student(); student.setName(小红); student.setAge(18); student.setSex(女); int code mapper.insert(student); session.commit(); // 事务提交 System.out.println(code); System.out.println(student.getId()); System.out.println(student); } Test public void delete() { int code mapper.delete(26); session.commit(); // 事务提交 System.out.println(code); } Test public void update() { Student student new Student(); student.setName(小宇); student.setAge(20); student.setSex(男); student.setId(28); int code mapper.update(student); session.commit(); // 事务提交 System.out.println(code); } Test public void findByName() { ListStudent students mapper.findByName(李); for (Student student : students) { System.out.println(student); } } Test public void findStudent() { ListStudent students mapper.findStudent(李, 1, 3); for (Student student : students) { System.out.println(student); } } Test public void findAllPerson() { Person person new Person(); Student student new Student(); student.setAge(25); student.setName(小宇); student.setSex(男); student.setId(28); person.setStudent(student); ListStudent students mapper.findAllPerson(person); for (Student student1 : students) { System.out.println(student1); } } }附录一核心对比速查表#{}vs${}对比#{}${}本质占位符预编译字符串拼接防注入✅❌简单类型命名任意写低版本必须value字符串引号自动加不自动加实体类属性必须是引用类型属性必须是引用类型属性入参类型速查类型parameterType写法示例简单类型java.lang.Integer/java.lang.StringfindById实体类com.qcby.entity.Studentinsert多参数无需parameterType用ParamfindStudent包装对象com.qcby.entity.PersonfindAllPerson出参类型速查操作resultType/resultMap说明查单条resultType实体类查多条resultType实体类框架自动组装List字段不匹配resultMap手动指定column→property增删改无需声明固定返回int
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门