转载本文请联系知点代码的公众号大叔。1前置概念01持久化持久化就是将数据保存到一个可以永久保存的存储设备上,比如磁盘。02JDBC在学习Java的过程中,大部分程序员在学习Java访问数据库的时候,都要先学习JDBC。它是一个JavaAPI,用于执行SQL语句,提供对数据库的统一访问,并将数据“持久化”到数据库中。我简单的解释一下(对JDBC有一定了解的同学可以跳过):Sun在1997年发布了JDK1.1,JDBC是这个版本中的一个重要技术点。正常的思路是Sun公司实现了如何连接数据库,如何执行SQL语句,但是市面上的数据库太多了,数据库之间的差异也非常大,Sun公司做不到公司了解每个数据库的内部细节。..所以为了让Java代码更好的和数据库对接,Sun制定了一系列的接口,叫做接口,其实是一套[标准],一套[标准]。具体代码如何实现取决于各个数据库厂商来敲代码;所以我们常说的“驱动类”就是各个厂商的实现类。所以当我们使用JDBC连接数据库时,第一步就是注册驱动,也就是告诉JVM使用哪个实现类来操作数据库。03ORM在没有ORM框架之前,我们需要这样操作数据库:可以看到,使用JDBC操作数据库,代码比较繁琐,SQL中参数拼写容易出错,可读性比较差差,增加了代码维护的难度。使用ORM框架,我们是这样操作数据库的:ORM框架在Java对象和数据库表之间做了一个映射,封装了数据库访问的细节。当我们需要操作数据库语句时,可以直接操作Java对象。向上。2.SpringBoot集成了MyBatisJava常用的ORM框架包括Hibernate、MyBatis、JPA等,我会在后面的文章中比较这种集中式框架的优缺点。本章主要介绍SpringBoot项目集成MyBatis访问数据库。步骤一、添加依赖mysqlmysql-connector-javaorg.mybatis.spring.bootmybatis-spring-boot-starter2.0.1第二步、配置数据库链接在application.yml文件中配置数据库相关信息。#数据源配置spring:datasource:#Databasedriverdriver-class-name:com.mysql.cj.jdbc.Driver#Databaseurrlurl:jdbc:mysql://127.0.0.1:3306/arch?characterEncoding=UTF-8&serverTimezone=UTC#usernameusername:root#passwordpassword:rootStep3.在我们本地数据库上配置数据库链接,创建用户表,插入一条数据:CREATETABLEIFNOTEXISTS`user`(`id`INTUNSIGNEDAUTO_INCREMENT,`userid`VARCHAR(100)NOTNULL,`username`VARCHAR(100)NOTNULL,`gender`CHAR(1)NOTNULL,`age`INTNOTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;insertintouser(userid,username,gender,age)values('大叔','叔叔','M',18);Step4.创建一个Model层,通常用来接收数据库中的数据对象。我将单独创建一个模型包。类中的属性用于保持字段相同。packagecom.archevolution.chapter4.model;publicclassUser{privateintid;//主键ID,自增长privateStringuserId;//用户ID,或者作为登录名privateStringuserName;//用户名privateStringgender;//性别privateintage;//年龄//省略get、set、toString方法}Step5.创建Dao层通常直接和数据库打交道的代码,我们把它们放在DAO层(DataAccessObject),所有的数据访问逻辑都在这里;我们新建一个dao包,在下面新建一个**interface**,注意接口:@MapperpublicinterfaceUserDao{@Select("SELECTid,userId,userName,gender,ageFROMUSERWHEREid=#{id}")publicUserqueryUserById(@Param("id")intid);}这里我多说几句!从技术角度来看,模型中的属性可以与表中的字段不同。比如我们在数据库中添加一个名为[mobilephone]的手机号码字段:--添加一个手机号码字段ALTERTABLEuserADDmobilephonevarchar(15);--更新userid=1的手机号码dataupdateusersetmobilephone='13800000000'whereuserid='1';我们在User.java中添加一个字段叫[telephone]:我们知道[telephone]和数据库中的[mobilephone]是对应的,但是如何让Mybatis知道这两个字段应该是对应的呢?有几种方式:01.在SQL语句中控制,给不同名称的字段起别名:@Select("SELECTid,userId,userName,gender,age,mobilephoneastelephoneFROMUSERWHEREid=#{id}")publicUserqueryUserTelById(@Param("id")intid);02.使用@Results标签映射不同属性和字段的设置(不能写重名):@Select("SELECTid,userId,userName,gender,age,mobilephoneFROMUSERWHEREid=#{id}")@Results({@Result(property="telephone",column="mobilephone")})publicUserqueryUserTelById2(@Param("id")intid);但是我还是建议你在写模型类的时候,属性和表中的字段保持完全一致,不仅降低了代码的复杂度,而且大大增加了代码的可读性,减少了出错的可能性;有的同学可能会有疑惑,数据结构很多项目的设计并不是那么规范,比如字段名可能是一个很奇怪的名字,比如flag01,flag02,如果这样的字段从数据库中查询出来,通过接口返回,接口的可读性会不会会不会太差了?通常我们不会将模型中的内容直接打包返回。很多t模型是数据库和Java对象之间的映射。传输数据时,通常需要DTO;我们从数据库中查询数据并将其放入模型中。在返回接口中的数据之前,把model转换成DTO,DTO中的属性需要保证其标准化和熟悉Step6.创建Service层我们的项目现在有Dao层访问数据,还有Controller层给用户提供接口访问,那么Controller可以直接调用Dao中的方法吗?最好不要直接打电话!通常我们会创建一个Service层来存储业务逻辑。此时完整的调用流程为:Controller-Service-Dao创建Service包后,在其中创建一个UserService:@ServicepublicclassUserService{@AutowiredUserDaouserDao;publicUserqueryUserById(intid){returnuserDao.queryUserById(id);}}Step7.在Controller层添加接口添加接口通过userId查询客户信息并返回客户信息:@RequestMapping(value="/queryUser/{id}")@ResponseBodypublicStringqueryUserById(@PathVariable("id")intid){Useruser=userService.queryUserById(id);returnuser==null?"Userisnotfind":user.toString();}Step8.测试验证在浏览器或客户端访问接口进行调试测试,可以查询客户信息:http://127.0.0.1:8088/queryUser/1User[id=1、userId=dashu,userName=uncle,gender=M,age=18,telephone=null]03MyBatis的其他操作只给出关键代码,完整代码请参考本章项目代码。01.添加@Insert("INSERTINTOUSER(userId,userName,gender,age)values"+"(#{userId},#{userName},#{gender},#{age})")publicvoidinsertUser(Useruser);02.修改@Update("UPDATEUSERSETmobilephone=#{telephone}WHEREid=#{id}")publicvoidupdateUserTel(Useruser);03.删除@??Delete("DELETEFROMUSERWHEREid=#{id}")publicvoiddeleteUserById(@Param("id")intid);4代码改进上面我们完成了最简单的SpringBoot和MyBatis的集成,可以正常读取数据库进行CRUD,但是因为是最简单的集成,还有一些细节需要改进,比如:参数都是它显示在url中;直接returnObject.toString()不太友好;无法查询到数据或出现异常,未做特殊处理;让我们逐步完善01.使用Json作为参数发送Post请求如果严格遵循Restful风格,那么需要遵循:查询:GET/url/xxx添加:POST/url修改:PUT/url/xxx删除:DELETE/url/xxx这里我们简单的认为在url里面写参数比较方便看我们的参数内容就可以了,如果参数多的话,url会很长,所以平时我们更习惯使用Json作为发送Post请求的参数。比如添加新User的接口可以这样写:AddanewDTOpackageandcreateanewUserDTO://使用Josn作为参数,需要设置headers={"content-type=application/json"}//@RequestBodyUserDtouserDto可以让JSON字符串自动Bind转换成UserD@RequestMapping(value="/insertUser2",headers={"content-type=application/json"})@ResponseBodypublicStringinsertUser2(@RequestBodyUserDtouserDto){//DTO进入ModelUseruser=newUser();用户。setUserId(userDto.getUserId());user.setUserName(userDto.getUserName());user.setGender(userDto.getGender());user.setAge(userDto.getAge());userService.insertUser(user);返回"Success";}AddUserinterface://使用Josn作为参数,需要设置headers={"content-type=application/json"}//@RequestBodyUserDtouserDto可以自动绑定并转换JSON字符串为UserDto@RequestMapping(value="/insertUser2",headers={"content-type=application/json"})@ResponseBodypublicStringinsertUser2(@RequestBodyUserDtouserDto){//DTO到ModelUseruser=newUser();user.setUserId(userDto.getUserId());user.setUserName(userDto.getUserName());user.setGender(userDto.getGender());user.setAge(userDto.getAge());userService.insertUser(user);return"Success";}下面调用接口测试:{"userId":"lisi","用户名":"李四","性别":"F","年龄":"40","电话":"18600000000"}02.标准返回参数直接返回Object.toString(),不太友好;让我们设计一个简单的返回引用对象,包括code-status代码,message-异常信息描述,data-data:代码,使用常用的:publicclassResponseCode{publicstaticfinalStringSUCCESS="200";//查询成功publicstaticfinalStringSUCCESS_NULL="204";//查询成功,但是没有数据publicstaticfinalStringPARAMETERERROR="400";//参数errorpublicstaticfinalStringFAIL="500";//Serverexception}这个时候我们重写查询接口:@RequestMapping(value="/queryUser2")@ResponseBodypublicJsonResponsequeryUser2ById(@RequestBodyUserDtouserDto){JsonResponseres=newJsonResponse();//province轻微参数校验Useruser=userService.queryUserById(userDto.getUserId());if(user!=null){//查询结果封装在返回引用res.setCode(ResponseCode.SUCCESS);res.setData(user);;}else{//如果找不到结果,返回'204'res.setCode(ResponseCode.SUCCESS_NULL);res.setMessage("Nodatafound");}returnres;}可以看到调用结果打包后的返回参考看起来是不是更规范:{"code":"200","message":null,"data":{"id":3,"userId":"lisi","userName":"Lisi"“性别”:“F”,“年龄”:40,“电话”:null}}03。异常处理如果代码运行过程中出现异常,如何处理?直接去掉exception是不是给前端返回了信息?这对调用者来说不是很友好。通常我们在本地打印错误日志,并返回一个异常状态码给调用者。向上抛出Service和Dao层的融合:publicUserqueryUserById(intuserId)throwsException{returnuserDao.queryUserById(userId);}在Controller层捕获异常并封装返回参数:Useruser=newUser();try{user=userService.queryUserById(userDto.getId());}catch(Exceptione){res.setCode(ResponseCode.FAIL);res.setMessage("ServiceException");}4MyBatisFAQ01.MyBatis为什么叫半自动ORM框架?有半自动的会有全自动的;Hibernate属于全自动ORM框架,使用Hibernate可以完全按照对象-关系模型进行操作,也就是说Java对象的操作不需要写SQL,所以是全自动的;而MyBatis关联对象,需要手动编写SQL语句,因此有“半自动”的说法。02.使用注解还是XML?相信大部分项目在使用MyBatis的时候,都是使用XML来配置SQL语句,而我们课程中的例子都是使用注解,那么这两者有什么区别呢?我们在开发的时候其实是如何选择的?首先,官方推荐使用XML,因为使用注解拼接动态SQL比较费力。如果你的SQL比较复杂,需要多表关联,还是用XML比较好;而且现在也有很多可以自动生成MyBatisXML的插件。但是事情总是有两个方面的,复杂的SQL并不是什么值得骄傲的事情,如果你的项目可以不用复杂的SQL,使用注解会是更好的选择(我们现在95%以上的项目都是SQL是单表查询).03.#{}和${}有什么区别?${}是字符串替换,#{}是预编译处理;使用#{}可以防止SQL注入,提高系统安全性。04.如何批量插入?注解也可以使用动态SQL:@Insert({""})publicvoidinsertUserList(@Param(value="userList")ListuserList);SpringBoot集成了MyBatis对数据库进行增删改查,属于比较基础的知识。对Java初学者很有帮助。