MyBatis操作数据库 📅 发布时间:2026/9/8 16:33:38 👁 浏览次数: 一、MyBatis的定义1.基本概念MyBatis是一种针对于数据库操作的持久层框架它与spring无关它的作用就是简化JDBC可以说它是针对JDBC的封装这样我们在spring项目中就能够更方便的操作数据库。2.回顾JDBCJDBC是我们在写Java代码时操作数据库的一套流程它的使用方法为在JDBC编程中有很多共性的地方可以使用配置信息、注解等操作来代替。首先需要创建一个DataSource对象:private final DataSource dataSource; public SimpleJdbcOperation(DataSource dataSource){ this.dataSource dataSource; }这里的DataSource对象是用来与数据库建立连接的。其次就是与数据库建立连接并且构建PreparedStatement对象之后再通过Connection对象创建sql语句最后通过PreparedStatement对象绑定参数、执行sql语句。public void queryBook() { Connection connection null; PreparedStatement stmt null; ResultSet rs null; Book book null; try { //获取数据库连接 connection dataSource.getConnection(); //创建语句 stmt connection.prepareStatement(select book_name, book_author, book_isbn from soft_bookrack where book_isbn ?); //参数绑定 stmt.setString(1, 9787115417305); //执⾏语句 rs stmt.executeQuery(); if (rs.next()) { book new Book(); book.setName(rs.getString(book_name)); book.setAuthor(rs.getString(book_author)); book.setIsbn(rs.getString(book_isbn)); } System.out.println(book); } catch (SQLException e) { //处理异常信息 } finally { //清理资源 try { if (rs ! null) { rs.close(); } if (stmt ! null) { stmt.close(); } if (connection ! null) { connection.close(); } } catch (SQLException e) { } } }这里stmt的作用有1.执行预编译的 SQL 语句2.用setString进行参数绑定也就是将第一个占位符和某个字符串绑定3.执行sql语句。二、使用MyBatis1.创建一个spring工程先new一个spring project之后就是一路创建并且填写组织ID、项目ID等字段前面以经说过这里就不再赘述。之后再选择Lombok依赖、SpringWeb依赖、MySQL Driver驱动依赖以及MyBatis Framework依赖就可以创建成功了。唯一需要注意的点就在这里剩下的还是删除一些plugin插件。2.引入关于MyBatis的一些依赖如果创建工程时没有选择的话MyBatis依赖!-- Mybatis 依赖包-- dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter-test/artifactId version4.0.1/version scopetest/scope /dependencyMySQL驱动依赖!--mysql驱动包-- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency3.引入数据库连接配置.YAML# 数据库连接配置 spring: datasource: # 在这里jdbc可以设置一下数据库名称以及密码等 url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncodingutf8useSSLfalse username: root password: password driver-class-name: com.mysql.cj.jdbc.Driver这里username是数据库用户名下面password是密码上面url包含了IP地址和端口号以及数据库名称后面则是编码方式。4.使用MyBatis写持久层代码4.1查找用户信息首先就是使用注解来查找用户信息这里的“Mapper”注解的作用与之前五大注解的作用类似都是将这个对象交给spring管理不过这样直接查询有一个不足的地方就是没有将数据库表中以下划线连接的字段与Java代码中的小驼峰形式的字段映射起来使得这里无法查询到某些字段的数据。Mapper public interface UserInfoMapper { //直接执行sql查询语句 Select(SELECT * FROM user_info) ListUserInfo selectList(); }4.2解决办法在这里一共有三种解决方法1.改变SQL语句将数据库表中的字段与Java变量关联起来//通过修改sql语句表示字段和Java属性的映射 Select(SELECT id, username, password, age, gender, phone, delete_flag AS deleteFlag, create_time AS createTime, update_time AS updateTime FROM user_info) ListUserInfo selectList2();但是写完之后我们会发现如果每个SQL语句都需要像这样写一大长串我们的工作量就会很大因此发明了第二种解决方案。2.使用Results注解实现字段和Java属性的映射:Results(value { //column就是数据库表中的字段 Result(column delete_flag,property deleteFlag), Result(column create_time,property createTime), Result(column update_time,property updateTime) }) Select(SELECT * FROM user_info) ListUserInfo selectList3();使用Results注解之后看着可读性就比较高了但是众所周知程序员要保证效率这里还有很多共性的地方因此可以利用注解中的id属性让所有想使用Results注解的语句都能够引用。使用id属性来使得所有引用Results的SQL语句都能映射Results(id BaseMap,value { //column就是数据库表中的字段 Result(column delete_flag,property deleteFlag), Result(column create_time,property createTime), Result(column update_time,property updateTime) }) Select(SELECT * FROM user_info) ListUserInfo selectList3(); //将Result注解变为可以被多个sql语句引用 ResultMap(value BaseMap) Select(SELECT * FROM user_info) ListUserInfo selectList4();这样既保证了注解引用的准确性又保证了引用注解的效率但是还是比较麻烦因此推出了第三种方法-开启驼峰命名。UserInfoMapper中指定的Results的id不能在其他类中使用。3.开启驼峰命名(推荐这种写法)开启驼峰命名可以使得每个使用驼峰命名的属性都能够被字段映射到mybatis: configuration: map-underscore-to-camel-case: true #配置驼峰⾃动转换4.3单元测试我们在做项目之后对于这个项目的第一个测试人员就应该是我们程序员自己因此在写完每个方法之后都可以对这个方法进行测试这也是单元测试。创建单元测试类的方法需要右键我们自己写完的方法点击Gennrate之后选择Test之后在下面勾选上自己想要测试的方法即可。创建之后在test目录下就会多出一个测试类同一个类中的方法在测试类中也是一一对应的这是idea自动生成测试代码如果想的话也可以手搓创建之后记得加上SpringBootTest注解方法上也要加上Test注解。5.MyBatis的一些基础操作5.1打印日志我们在工作时难免需要打印一些日志使用MyBatis操作数据库时也是如此因此这里可以引入打印MyBatis日志的配置文件# 配置打印 MyBatis⽇志 mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl加上这些配置之后测试的时候就能看见日志了。5.2参数传递在构造SQL语句时会存在一些情况就是将暂时不想写死的条件用一个占位符代替比如select book_name, book_author, book_isbn from soft_bookrack where book_isbn ?在MyBatis中要传递参数也很简单就是将“”改为“#{}”即可。Mapper public interface UserInfoMapper2 { //传递参数通过传递一个Integer类型的参数来实现查找 Select(select id,username, password, age, gender, phone from user_info where id #{id} ) ListUserInfo selectById(Integer id); }如果只是单个参数的传递那么这个参数可以是任意名称即使参数和“#{}”中的内容对不上JDK也会自动填充但是如果是多个参数的话就不可以了。//如果只有一个参数那么可以随意传名称不建议这么写 Select(select id,username, password, age, gender, phone from user_info where id #{ada} ) ListUserInfo selectById2(Integer id);如果时传递多个参数就不能随意填写了必须要一一对应不过对于这种情况JDK给了一个新的方案就是使用Parami第几个参数从1开始来进行参数传递但是这样的话以后再加入新的传参会很麻烦。Select(SELECT * FROM user_info where age #{age} and gender #{gender}) ListUserInfo selectByAgeAndGender(Integer age, Integer gender); Select(SELECT * FROM user_info where age #{param1} and gender #{param2}) ListUserInfo selectByAgeAndGender(Integer age, Integer gender);传递参数如果不想使用参数的原名可以使用Param注解来修改名称。//实在是想改名可以利用Param注解 Select(SELECT * FROM user_info where age #{Age} and gender #{Gender}) ListUserInfo selectByAgeAndGender2(Param(Age) Integer age, Param(Gender) Integer gender);传递的参数如果是对象的话传进去的参数可以直接使用对象中的属性名//如果传递参数是对象的话那么传递的名称要和对象中的属性名一致 Select(SELECT * FROM user_info where age #{age} and password #{password}) ListUserInfo selectByAgeAndGender3(UserInfo userInfo);NoArgsConstructor Data public class UserInfo { private Integer id; private String username; private String password; private Integer age; private Integer gender; private String phone; private Integer deleteFlag; private Date createTime; private Date updateTime; public UserInfo(String username, String password, Integer age) { this.username username; this.password password; this.age age; } }如果使用了param注解修改了对象的名称那么在传递参数时需要用对象.属性名的方式传递参数//传递参数为对象并且修改了名称之后需要在传递属性时变为名称属性名 Insert(insert into user_info (username, password, age) VALUE(#{use.username}, #{use.password}, #{use.age} )) Integer insertUser(Param(use) UserInfo userInfo);获取表中的自增id可以使用Options注解//这个注释的作用是插入时获取自增id Options(useGeneratedKeys true,keyProperty id) Insert(insert into user_info (username, password, age) VALUE(#{use.username}, #{use.password}, #{use.age} ))useGeneratedKeys属性的作用就是让 MyBatis 使用 JDBC 的Statement . getGenerate dKeys() 方法获取数据库内部生成的值并将其赋值给了userInfo对象的id属性后续可以使用get方法获取到id值。5.3增删查改操作//查找数据 Select(SELECT * FROM user_info) ListUserInfo selectList(); //增加数据 Insert(insert into user_info (username, password, age) VALUE(#{use.username}, #{use.password}, #{use.age} )) Integer insertUser(Param(use) UserInfo userInfo); //删除数据 Delete(delete from user_info where id #{id}) Integer deleteUser(Integer integer); //修改数据 Update(update user_info set gender #{gender}, delete_flag #{deleteFlag} where id #{id}) Integer updateUser(UserInfo userInfo);三、使用XML配置文件来实现mybatis开发1.配置连接字符串和MyBatismybatis开发有两种方式一种是注解另一种则是使用XML要使用XML配置文件来实现mybatis开发。首先就是引入数据库连接配置和设置xml文件识别的文件地址。# 数据库连接配置 spring: application: name: spring-mybatis-demo datasource: # 在这里jdbc可以设置一下数据库名称以及密码等 url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncodingutf8useSSLfalse username: root password: mazixuan driver-class-name: com.mysql.cj.jdbc.Driver # 配置打印 MyBatis⽇志 mybatis: # 配置 mybatis xml 的⽂件路径在 resources 创建所有表的 xml ⽂件 # 这里的classpath就相当于resources文件夹mybatis关心xml文件的名字,路径和名称都要一致 mapper-locations: classpath:mybatis/UserInfoMapperXML.xml configuration: # 配置自动打印日志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true #配置驼峰⾃动转换这里mapper-locations:表示的就是识别哪个文件中的sql语句。2.引入MyBatis依赖和MySQL驱动这个之前就已经引入过了不必多说。!-- Mybatis 依赖包-- dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version4.0.1/version /dependency!--mysql驱动包-- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency3.在resource目录下创建.xml文件这个文件就是存放SQL语句的文件其中文件名称可以随意不过一般公司都会有规范跟着规范来即可不过要注意这个路径以及名称要与前面MyBatis配置文件中的mapper-locations:后面的路径和名称保持一致。?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.shanxi.mazixuan.mapper.UserInfoMapperXML /mapper这里namespace的路径加类名是你开发时使用的持久层接口的路径和类名。4.写持久层代码4.1查询语句Mapper层代码package com.shanxi.mazixuan.mapper; import com.shanxi.mazixuan.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; Mapper public interface UserInfoMapperXML { ListUserInfo selectList(); }.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.shanxi.mazixuan.mapper.UserInfoMapperXML !-- 一个接口只对应一个XML-- select idselectList resultTypecom.shanxi.mazixuan.model.UserInfo select * from user_info /select /mapper这里可以下载一个名为MyBatisX的一个插件它能够在写接口时根据方法名猜测配置文件中需要什么标签比如你的方法名为selectList()那么它会根据这个名称推断你需要select标签来查询数据。4.2映射键值对映射sql中的字段与类中的成员变量与注解的类似1.直接在sql语句中使用as2.配置使用自动转换驼峰3.指定映射关系ListUserInfo selectList2(); ListUserInfo selectList3(String sort);转换驼峰和使用as的之前也都有无非就是在sql中或在配置文件中体现这里指定映射关系select idselectList2 resultTypecom.shanxi.mazixuan.model.UserInfo SELECT id, username, password, age, gender, phone, delete_flag AS deleteFlag, create_time AS createTime, update_time AS updateTime FROM user_info /selectresultMap idBaseMap1 typecom.shanxi.mazixuan.model.UserInfo id columnid propertyid/id result columndelete_flag propertydeleteFlag/result result columncreate_time propertycreateTime/result result columnupdate_time propertyupdateTime/result /resultMap select idselectList3 resultMapBaseMap1 !-- 使用$符号时需要注意sql注入的问题-- !-- 可以使用MySQL内置的方法concat方法来处理-- !-- select * from user_info Order By id ${sort}-- select * from user_info where username like concat(%,#{username},%) /select映射时需要注意标签的id和type两个属性id可以随便起名type需要指定实体类也就是model层的对象。4.3使用xml进行传参Integer insertUser(UserInfo userInfo); Integer insertUser2(Param(userInfo) UserInfo userInfo);xml传参的规则与注解传参一致不过XML文件中对于空格/换行等是无效的不影响执行!-- 使用XML传参与注解传参的规则是一样的-- insert idinsertUser insert into user_info (username, password, age) VALUE(#{username}, #{password}, #{age} ) /insert insert idinsertUser2 useGeneratedKeystrue keyPropertyid insert into user_info (username, password, age) VALUE(#{userInfo.username}, #{userInfo.password}, #{userInfo.age} ) /insert4.4删除和更新Integer deleteUserById(Integer id); Integer updateUser(UserInfo userInfo);delete iddeleteUserById delete from user_info where id #{id} /delete update idupdateUser update user_info set gender #{gender}, delete_flag #{deleteFlag} where id #{id} /update四、多表查询package com.shanxi.mazixuan.mapper; import com.shanxi.mazixuan.model.ArticleInfo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; Mapper public interface ArticleInfoMapper { Select(select ta.*, tb.username, tb.age from article_info ta left join user_info tb on ta.uid tb.id where ta.id #{id}) ArticleInfo queryArticleInfo(); }针对于多表查询只能说与单表查询的不同点只在于SQL语句不同其他的关于MyBatis的使用都是一样的。五、#{}和${}的区别1.主要不同点这两个符号的区别主要在于1.#{}是预编译SQL${}是即使SQL这一点在运行时的日志中的sql语句有所体现2.#{}能够预防SQL注入${}不能3.当传递的参数是String类型时需要添加‘’但是${}不会拼接‘’需要程序员在编写SQL时手动加上‘’。2.#{}相比于${}的优点1.性能更好预编译SQL的性能更高它编译一次之后会将编译的SQL缓存起来下次再使用时无需再重复编译和优化SQL的步骤2.更安全防止SQL注入预编译SQL会先检查一遍SQL语句如果存在SQL注入会不通过。3.${}的使用场景${}在一定的场景下也需要被用到这也是它没有被优化的原因比如在排序的场景它就能够被使用到。Select(select id, username, age, gender, phone, delete_flag, create_time, update_time from user_info order by id #{sort} ) List queryAllUserBySort(String sort);这里使用#{}就会报错因为编译器会将其中的sort前后加上‘’导致sql错误。4.like查询Select(select id, username, age, gender, phone, delete_flag, create_time, update_time from user_info where username like %#{key}% ) List queryAllUserByLike(String key);当使用#{}时就会报错原因也是他会自动加上‘’但是使用${}又会存在sql注入的问题因此可以使用mysql的内置方法concat()来处理也就是将%#{key}%改为concat(%,#{key},%),这个方法可以让这三个拼接起来。六、数据库连接池在使用MyBatis框架时用到了数据库连接池这与常量池以及线程池等类似是指在创建connection连接时在一个容器中存放几个现成的连接当需要使用时就从这个池中取等到释放时还会继续存放进去以便下次使用这样既提高了效率还减少了网络开销实现了资源重用。不过MyBatis框架本身是不提供数据库连接池的只是有一些组件提供了这个功能例如C3P0 、 DBCP 、 Druid 、 Hikari目前比较流行的是Hikari 和Druid如果要使用数据库连接池只需要引入依赖和配置文件即可dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-3-starter/artifactId version1.2.21/version /dependency如果spring-boot是2.*版本使用这个依赖dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.1.17/version /dependency