SpringBoot整合MyBatis
------ 既然你都开始整合Mybatis了,我相信基本的SpringBoot项目创建你自己肯定是可以搞定的,所以我在这里就不多赘述了,话不多B,让我们直奔主题
MyBatis---半自动ORM框架
现如今,常见的持久层框架有:Hibernate,MyBatis , JPA....
相对于Hibernate来说,MyBatis更容易上手一些
今天我就把SpringBoot如何整合Mybatis给大家演示一下,共同学习。
如果有没有接触过这两个技术栈的小伙伴,那你们可以先去康康,稍后再来~~。
这是一段来自百度百科的权威解释
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。 MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。
项目框架
Maven的pom.xml文件
需要导入的依赖---可以在创建SpringBoot项目时可以勾选导入的技术栈
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cody</groupId> <artifactId>sbootmybatis</artifactId> <version>0.0.1-SNAPSHOT</version> <name>sbootmybatis</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <resources> <!--此处的配置是识别到mapper.xml文件,也可以在application.properties中配置--> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </build></project>
mapper配置文件
UserMapper.xml
==注意文件的位置==
<?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"><!-- namespace:改mapper.xml映射文件的唯一标识并且必须和数据处理层的接口的路径相同--><mapper namespace="com.cody.sbootmybatis.sbootmybatis.mapper.UserMapper"><!-- 必须添加property属性 ,区别于是否加主键--> <resultMap id="user" type="User"> <id column="userid" property="userid" javaType="int" ></id> <result column="username" property="username" javaType="String" ></result> <result column="userage" property="userage" javaType="int" ></result> <result column="userpwd" property="userpwd" javaType="String" ></result> </resultMap> <!--id的值必须和数据处理层的接口名一致--> <!--此处的User--> <select id="queryAlluser" resultType="User"> select * from user </select> <select id="queryuserbyid" parameterType="int" resultMap="user" resultType="User"> select * from user <trim suffixOverrides="and" prefixOverrides="and"> <where> <if test="userid!=null"> and userid = #{userid} </if> </where> </trim> </select> <select id="queryuserbyname" resultType="User" parameterType="string" resultMap="user"> select * from user <trim suffixOverrides="and" prefixOverrides="and"> <where> <if test="username!=null"> and username = #{username} </if> </where> </trim> </select> <update id="UpdUser" parameterType="User"> </update> <delete id="DelUser"></delete> <insert id="AddUser" parameterType="User" > insert into user value (${userid},#{username},${userage},#{userpwd}) </insert></mapper>
application.properties的配置
# 端口的配置server.port=8081# 数据库访问配置spring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver#将database_name改成自己的数据库的名称spring.datasource.url=jdbc:mysql://localhost:3306/database_name?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8spring.datasource.username=rootspring.datasource.password=123456
application.yml的配置
# 配置Mybatis的包的别名,在mapper.xml文件中xxxType="xxx" 此处直接可以写实体类的类名即可,不需要将全类名都写上#<select id="queryAlluser" resultType="User"># select * from user# </select>#<select id="queryAlluser" resultType="com.xxx.xxx.entity.User"># select * from user# </select>mybatis: type-aliases-package: com.xxx.xxx.entity #禁用掉模板缓冲,在开发环境中可以实时的观察到html页面的更改 spring: thymeleaf: cache: false
controller
logincontroller.java
/** loginController 简单的登录测试 与index.html一起使用*/import com.cody.sbootmybatis.sbootmybatis.entity.User;import com.cody.sbootmybatis.sbootmybatis.mapper.UserMapper;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import javax.annotation.Resource;import java.util.Map;/** * @author xxx * @date 2020/5/6 - 10:09 */@Controllerpublic class logincontrollor { @Resource private UserMapper userMapper; @RequestMapping(value = "/user/login" ,method = RequestMethod.POST) @ResponseBody public String login(@RequestParam("username") String username , @RequestParam("password")String password , Map<String,Object> map){ User user=userMapper.queryuserbyname(username); if (username.equals(user.getUsername())&&password.equals(user.getuserpwd())){ return "登录成功"; } else{ return "登录失败"; } }}
mycontroller.java
/** 增删改查*/package com.cody.sbootmybatis.sbootmybatis.controllor;import com.cody.sbootmybatis.sbootmybatis.mapper.UserMapper;import com.cody.sbootmybatis.sbootmybatis.entity.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController@RequestMapping("/user")public class mycontroller { @Autowired(required = false) private UserMapper userMapper; @RequestMapping(value ={"/queryAlluser"},method = RequestMethod.GET) /** * * * @return List<User> * * * */ public List<User> queryalluser(){ List<User> list = userMapper.queryAlluser(); return list; } @RequestMapping(value = {"/queryuserbyid"} , method = RequestMethod.GET) /** * * * @param userid * @return user * * */ public User queryuserbyid(String userid){ User user = userMapper.queryuserbyid(Integer.parseInt(userid)); return user; } @RequestMapping(value = {"/adduser"} , method = RequestMethod.GET) /** * * * @param useri * @return user * * */ public String adduser(User user){ boolean flag = userMapper.AddUser((User) user); return flag ?"success":"fail"; } @RequestMapping(value = {"/Upuserbyid"} , method = RequestMethod.GET) /** * * * @param userid * @return user * * */ public String Upuser(User user){ boolean flag = userMapper.UpdUser((User) user); return flag?"success":"fail"; } @RequestMapping(value = {"/Deluserbyid"} , method = RequestMethod.GET) /** * * * @param userid * @return user * * */ public String Deluserbyid(String userid){ boolean flag = userMapper.DelUser(Integer.parseInt(userid)); return flag?"success":"fail"; }}
mapper
package com.cody.sbootmybatis.sbootmybatis.mapper;import com.cody.sbootmybatis.sbootmybatis.entity.User;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import java.util.List;/** * @author Cody * @date 2020/5/2 - 13:25 * @Decription : */@Mapperpublic interface UserMapper { /** *查 读取(Retrieve) * fetch data * @return List<User> */ List<User> queryAlluser(); /** *查 读取(Retrieve) * fetch data by userid * @param userid * @return User */ /** @Select("select * from user where userid = #{userid}") 本人喜欢讲SQL语句写在mapper.xml文件中,这样显得代码比较整齐 在后期开发中,一旦SQL语句变得繁琐起来,不利于维护 但是这样用注解的形式也完全可行,毕竟有些人可能写配置文件可能已经快写吐了 */ User queryuserbyid( int userid); /** * 增加(Create) * add data by user * @param user * @return int */ boolean AddUser(User user); /** * 删除(Delete) * @param id * @return int */ boolean DelUser(int id); /** * 更新(Update) * @param user * @return boolean */ boolean UpdUser(User user); User queryuserbyname(String name);}
前端
将index.html文件放在template文件夹下
<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head> <meta charset="UTF-8"> <title>Title</title></head><body ><form method="post" action="/user/login" > <input name="username" type="text" placeholder="请输入用户名"/> <input type="password" name="password" /> <input type="submit" th:value="登录"/></form></body></html>
测试
测试登录操作
数据库的信息:
测试CRUD(即增删改查)
查询全部
根据ID查询
增加User
通过?和&传值
注意事项
1.mappe.xml文件的路径包括文件名必须同数据层的接口完全一致
2.application.properties文件和application.yml文件不需要都写,二选一即可,只不过这里我都写了而已
使开发更加便利的IDEA插件
给大家安利一款IDEA插件 : MyBatisX
作用: 在接口中写方法可以直接在mapper.xml文件中写CRUD方法生成相应的标签
图中使用的快捷键是 :==alt+enter==
MyBatis框架的优点
- 与JDBC相比,减少了50%以上的代码量。
- MyBatis是最简单的持久化框架,小巧并且简单易学。
- MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用。
- 提供XML标签,支持编写动态SQL语句。
- 提供映射标签,支持对象与数据库的ORM字段关系映射。
MyBatis框架的缺点
- SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写SQL语句的功底有一定要求。
- SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
SpringBoot整合Mybatis中遇到的Errors
这是我自己在整合的时候遇到的一些问题,希望自己走过的弯路可以多多帮助到大家。
There was an unexpected error (type=Internal Server Error, status=500).Error attempting to get column 'u_account' from result set. Cause: java.sql.SQLDataException: Cannot determine value type from string '201577D0510' ; Cannot determine value type from string '201577D0510'; nested exception is java.sql.SQLDataException: Cannot determine value type from string '201577D0510'org.springframework.dao.DataIntegrityViolationException: Error attempting to get column 'u_account' from result set. Cause: java.sql.SQLDataException: Cannot determine value type from string '201577D0510'; Cannot determine value type from string '201577D0510'; nested exception is java.sql.SQLDataException: Cannot determine value type from string '201577D0510' at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:84) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) at com.sun.proxy.$Proxy65.selectList(Unknown Source)
解决方法:
添加了entity子类中的无参构造方法,异常消失
java.sql.SQLException: Access denied for user ''@'localhost' (using password: NO) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:836) at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:456) at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:246)
解决方法:==时区报错==
更改配置信息:
spring: datasource: username: root password: 123456 # 如果时区报错就需要添加 serverTimezone=UTC url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver
使用@Autowired注解有错误提示
使用Spring boot +mybatis框架时,在service实现类中使用Mapper类,给Mapper类添加@Autowired注解时发现有错误提示:could not autowire,no beans of "XXX" type found,但程序的编译和运行都正常。处理方式:方案一:@Autowired(required = false) 设置required 属性值为 false,错误消失方案二:用@Resource注解替换@Autowired注解,错误消失@Resource注解与@Autowired注解的异同点这两个注解都是用作bean的注入时使用,都是为一个对象变量省去写get,set方法,自动为这个对象注入实例化对象(即注入依赖)注入的方式还是有所区别的 :@Autowired是基于spring的注解org.springframework.beans.factory.annotation.Autowired,它默认是按类型进行的装配的,如果想要它按名字进行装配则需在@autowired下面添加@qualifier("name")`注解,都无法找到唯一的一个实现类的时候报错。@Autowired注解默认情况下必须要求依赖对象必须存在,如果要允许null值,则应该设置它的required属性为false,@Resource 是基于j2ee的注解(可以减少了与spring的耦合),(JDK1.6以上支持)默认是按名字进行注解,若不指定装配bean的名字,当注解写在字段上时,默认取字段名,按照名称查找通过set方法进行装配,倘若有多个子类,则会报错。需要注意的是name属性一旦指定,就只会按照名称进行装配
解与@Autowired注解的异同点
这两个注解都是用作bean的注入时使用,都是为一个对象变量省去写get,set方法,自动为这个对象注入实例化对象(即注入依赖)注入的方式还是有所区别的 :
@Autowired是基于spring的注解org.springframework.beans.factory.annotation.Autowired,它默认是按类型进行的装配的,如果想要它按名字进行装配则需在@autowired下面添加@qualifier("name")`注解,都无法找到唯一的一个实现类的时候报错。@Autowired注解默认情况下必须要求依赖对象必须存在,如果要允许null值,则应该设置它的required属性为false,
@Resource 是基于j2ee的注解(可以减少了与spring的耦合),(JDK1.6以上支持)默认是按名字进行注解,若不指定装配bean的名字,当注解写在字段上时,默认取字段名,按照名称查找通过set方法进行装配,倘若有多个子类,则会报错。需要注意的是name属性一旦指定,就只会按照名称进行装配
``
The Ending
----------每天进步“亿”点点----------
-----Relyonyouself--