乐趣区

SpringBoot整合Mybatis

SpringBoot 整合 MyBatis

—— 既然你都开始整合 Mybatis 了,我相信基本的 SpringBoot 项目创建你自己肯定是可以搞定的,所以我在这里就不多赘述了,话不多 B,让我们直奔主题

MyBatis— 半自动 ORM 框架

现如今,常见的持久层框架有:HibernateMyBatis , 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.DruidDataSource
spring.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-8
spring.datasource.username=root
spring.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
 */
@Controller
public 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 :
 */
@Mapper
public 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 框架的优点

  1. 与 JDBC 相比,减少了 50% 以上的代码量。
  2. MyBatis 是最简单的持久化框架,小巧并且简单易学。
  3. MyBatis 相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用。
  4. 提供 XML 标签,支持编写动态 SQL 语句。
  5. 提供映射标签,支持对象与数据库的 ORM 字段关系映射。

MyBatis 框架的缺点

  1. SQL 语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写 SQL 语句的功底有一定要求。
  2. 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–

退出移动版