什么是MyBatis
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
官方文档: https://mybatis.org/mybatis-3/zh/getting-started.html
持久层 定义:
数据持久化
持久化就是将程序的数据在持久状态和瞬时状态转化的过程
内存:断电即失
数据库(jdbc)、io文件持久化
为什么需要持久化
为何选择MyBatis
灵活性:MyBatis允许您直接编写原生的SQL语句,提供了很高的灵活性。您可以根据需要编写任何复杂的SQL,从而满足各种业务需求
易于使用:MyBatis通过XML配置文件和注解,让您可以轻松地将SQL语句与Java代码分离,使得代码结构更清晰、易于维护
映射简单:MyBatis提供了简单的映射方式,可以将数据库表中的字段自动映射到Java对象的属性上,降低了数据转换的复杂性
良好的扩展性:MyBatis提供了丰富的插件接口,您可以通过编写自定义插件来扩展MyBatis的功能,以满足特定需求
与其他框架集成:MyBatis可以与Spring、Spring Boot等流行框架无缝集成,提供更加完整的解决方案
社区支持:MyBatis有一个活跃的开发者社区,为使用者提供了丰富的文档、教程和支持。这有助于在遇到问题时快速找到解决方案
MyBatis框架解决JDBC劣势 针对JDBC编程的劣势,MyBatis提供了以下解决方案,具体如下。
问题一:数据库链接创建、释放频繁会造成系统资源浪费,从而影响系统性能。
解决方案:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
问题二:SQL语句在代码中硬编码,造成代码不易维护。在实际应用的开发中,SQL变化的可能较大。在传统JDBC编程中,SQL变动需要改变Java代码,违反了开闭原则。
解决方案:MyBatis将SQL语句配置在MyBatis的映射文件中,实现了与Java代码的分离。
问题三:使用preparedStatement向占位符传参数存在硬编码,因为SQL语句的where条件不一定,可能多也可能少,修改SQL需要修改代码,造成系统不易维护。
解决方案:MyBatis自动将Java对象映射至SQL语句,通过Statement中的parameterType定义输入参数的类型。
问题四:JDBC对结果集解析存在硬编码(查询列名),SQL变化导致解析代码变化,造成系统不易维护。
解决方案:MyBatis自动将SQL执行结果映射至Java对象,通过Statement中的resultType定义输出结果的类型。
学习示例(注释版) 新建一个user数据库: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 create database `user `use `user ` create table `user_table`( `id` int (20 ) not null auto_increment, `user_name` varchar (32 ) not null , `sex` int (1 ) default null , `age` int (20 ) default null , `register_time` datetime CURRENT_TIMESTAMP , `create_time` datetime CURRENT_TIMESTAMP , `update_time` datetime CURRENT_TIMESTAMP , primary key(`id`) ); insert into user_table values ('张三' ,'1' ,'29' );insert into user_table values ('李四' ,'0' ,'27' );insert into user_table values ('王五' ,'1' ,'39' );
pom.xml文件里面导入MyBatis相关jar包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 2.0.0</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-jdbc</artifactId > </dependency >
application.yml文件中配置数据库连接信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: linkurl... username: username password: password type: com.zaxxer.hikari.HikariDataSource hikari: minimum-idle: 5 maximum-pool-size: 15 auto-commit: true idle-timeout: 30000 pool-name: DatebookHikariCP max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: SELECT 1
将工程目录按照层划分
controller:此目录主要是存放Controllerde ,比如:UserController.java,也有的项目是把action放在controller目录下,有的是把UserController.java放在action目录下。
service:这里分接口和实现类,接口在service目录下,接口实现类在service/impl目录下。
dao:持久层,目前比较流行的Mybatis或者jpa之类的。
controller下创建实体类 Controller层通常用于处理HTTP请求并充当应用程序的接口入口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 package com.test.controller;import com.test.handler.exception.BodyDecryptException;import com.test.model.Result;import com.test.model.User;import com.test.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.List;import java.util.Map;@RestController @RequestMapping(value = "/user") public class UserController extends Result { @Autowired private UserService userService; @RequestMapping(value = "/getUserInfo", method = RequestMethod.GET) public String getUserInfo (Integer id) { return userService.getUserInfo(id); } @RequestMapping(value = "/getAllUserInfo", method = RequestMethod.GET) public String getAllUserInfo () { return userService.getAllUserInfo(); } @PostMapping(value = "/addUser") public String addUser (@RequestBody Map<String, String> user) throws BodyDecryptException { return userService.addUserInfo(user); } @PostMapping(value = "/addUser/batchImport") public String batchImport (@RequestBody List<User> params) { return userService.batchAddUserInfo(params); } @RequestMapping(value = "/updateUser", method = RequestMethod.PUT) public String updateUser (@RequestBody Map<String, String> user) { return userService.updateUserInfo(user); } @RequestMapping(value = "/deleteUser", method = RequestMethod.DELETE) public String deleteUser (Integer id) { return userService.deleteUser(id); } @RequestMapping(value = "/deleteUser/batchDelete", method = RequestMethod.DELETE) public String batchDeleteUser (String[] ids) { return userService.batchDeleteUser(ids); } }
dao下创建UserDao DAO(数据访问对象)层是用于与数据库进行交互的层。它负责执行数据库操作,包括查询、插入、更新和删除数据。
创建Mapper接口,使用注解方式定义SQL查询和操作方法。这里示例对user_table进行增删改查的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 package com.test.dao;import com.test.model.User;import org.apache.ibatis.annotations.*;import java.util.List;import java.util.Map;@Mapper public interface UserDao { @Results(id = "UserResultMap", value = { @Result(property = "id", column = "id"), @Result(property = "userName", column = "user_name"), @Result(property = "sex", column = "sex"), @Result(property = "age", column = "age"), @Result(property = "birthday", column = "birthday"), @Result(property = "registerTime", column = "register_time"), @Result(property = "createTime", column = "create_time") }) @Select("select * from user_table where id = #{id}") User getUserInfoById (Integer id) ; @ResultMap("UserResultMap") @Select("select * from user_table") List<User> getAllUserInfo () ; @Insert("insert into user_table (user_name, sex, age, birthday) values" + "(#{userName}, #{sex}, #{age}, #{birthday})") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") void addUser (Map<String, String> param) ; @Insert("<script>" + "insert into user_table (user_name, sex, age, birthday) values " + "<foreach collection='list' item='item' index='index' separator=','>" + "(#{item.userName}, #{item.sex}, #{item.age}, #{item.birthday})" + "</foreach>" + "</script>") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") void batchAddUser (@Param("list") List<User> paramList) ; @Delete("delete from user_table where id = #{id}") void deleteUser (Integer id) ; @Delete("<script>" + "delete from user_table where id in " + "<foreach collection='array' item='id' open='(' separator=',' close=')'>" + "#{id}" + "</foreach>" + "</script>") void batchDeleteUser (String[] idList) ; @Update("<script>" + "update user_table set " + "user_name = #{userName}, " + "sex = #{sex}, " + "<if test = 'age != null'> age = #{age}, </if> " + "birthday = #{birthday} " + "where id = #{id}" + "</script>") void updateUser (Map<String, String> userInfo) ; }
在启动类下面配置MyBatis 在Spring Boot配置类上添加 @MapperScan
注解来扫描Mapper接口的包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com.test;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.EnableScheduling;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;@SpringBootApplication @EnableAsync @EnableScheduling @MapperScan("com.test.dao") public class AiSenEnvApplication { public static void main (String[] args) { SpringApplication.run(AiSenEnvApplication.class, args); } @Bean(name = "executorPool") public ExecutorService executorPool () { int curSystemThreads = Runtime.getRuntime().availableProcessors(); System.out.println("线程个数:" + curSystemThreads); ExecutorService pool = Executors.newFixedThreadPool(curSystemThreads); return pool; } }
启动应用程序 调用controller层接口测试数据的增删改查
学习示例(使用XML配置来执行基本的CRUD操作) 配置数据库连接信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: linkurl... username: username password: password type: com.zaxxer.hikari.HikariDataSource hikari: minimum-idle: 5 maximum-pool-size: 15 auto-commit: true idle-timeout: 30000 pool-name: DatebookHikariCP max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: SELECT 1
配置MyBatis扫描项目mapper的目录 application.yml文件中进行如下配置:
1 2 3 4 5 mybatis: mapperLocations: classpath:mapper/*.xml
创建MyBatis映射文件 src/main/resources/mapper下创建UserManageMapper.xml,在这里将通过XML定义SQL语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 <?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.test.dao.UserDao" > <resultMap id ="UserResultMap" type ="com.test.model.User" > <result property ="id" column ="id" /> <result property ="userName" column ="user_name" /> <result property ="age" column ="age" /> <result property ="sex" column ="sex" /> <result property ="birthday" column ="birthday" /> <result property ="registerTime" column ="register_time" /> <result property ="createTime" column ="create_time" /> </resultMap > <select id ="getAllUserInfo" resultMap ="UserResultMap" > select * from user_table </select > <insert id ="addUser" parameterType ="java.util.Map" > insert into user_table (user_name, sex, age, birthday) VALUES (#{userName}, #{sex}, #{age}, #{birthday}) </insert > <insert id ="batchAddUser" parameterType ="java.util.List" > insert into user_table (user_name, sex, age, birthday) VALUES <foreach collection ="list" item ="item" index ="index" separator ="," > (#{item.userName}, #{item.sex}, #{item.age}, #{item.birthday}) </foreach > </insert > <update id ="updateUser" > update user_table set <if test ="userName != null and userName != ''" > user_name = #{userName}, </if > <if test ="sex != null and sex != ''" > sex = #{sex}, </if > age = #{age}, <if test ="birthday != null" > birthday = #{birthday} </if > where id = #{id} </update > <delete id ="deleteUser" parameterType ="integer" > delete from user_table where id = #{id} </delete > <delete id ="batchDeleteUser" > delete from user_table where id in <foreach collection ="array" item ="id" index ="index" open ="(" separator ="," close =")" > #{id} </foreach > </delete > </mapper >
dao下创建UserDao 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.test.dao;import com.test.model.User;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import java.util.List;import java.util.Map;@Mapper public interface UserDao { User getUserInfoById (Integer id) ; List<User> getAllUserInfo () ; void addUser (Map<String, String> param) ; void batchAddUser (@Param("list") List<User> paramList) ; void deleteUser (Integer id) ; void batchDeleteUser (String[] idList) ; void updateUser (Map<String, String> userInfo) ; }
测试 使用api工具测试CRUD,全部通过