SpringBoot+Mybatis+MySQL


在学习SpringBoot时想连接数据库做一些操作,从网上找了一些博客,总感觉很多解释的不清楚。自己写一篇总结,主要是本人使用中踩过的坑。

1.准备两张带有级联关系的数据表User表和Department表,先创建Department表,在User表中维护关联关系,并向Department表中添加数据。

CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

INSERT INTO `department` VALUES (1, '研发部');
INSERT INTO `department` VALUES (2, '销售部');
INSERT INTO `department` VALUES (3, '测试部');
INSERT INTO `department` VALUES (4, '商品部');
INSERT INTO `department` VALUES (5, '采购部');

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `password` varchar(45) NOT NULL,
  `identify_type` tinyint(4) NOT NULL,
  `identify_number` varchar(45) NOT NULL,
  `dept_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_user_dept` (`dept_id`),
  CONSTRAINT `fk_user_dept` FOREIGN KEY (`dept_id`) REFERENCES `department` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

2.添加Maven依赖,只添加这块需要用到的依赖,MySQL驱动,MyBatis,Lombok,以及用于测试的test,其它依赖项没有展示。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>    
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.1</version>
</dependency>

3.创建POJO对象。因添加有lombok,使用@Data注解,可以代替getter/setter方法。生成一个无参构造器和全参构造器。

package com.cn.entities.mysql;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Department {
    private Integer id;
    private String name;
}
package com.cn.entities.mysql;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id;
    private String name;
    private String password;
    private Integer identifyType;
    private String identifyNumber;
    private Department department;
}

4.在application.properties中配置MySQL和MyBatis。

spring.datasource.url=jdbc:mysql://localhost/test?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis.type-aliases-package=com.cn.entities.mysql
mybatis.mapper-locations=classpath:mapper/*.xml
server.port=8081

需要注意的有以下几点

  • MySQL驱动版本不同,driver-class-name使用com.mysql.cj.jdbc.Driver而不是原来的com.mysql.jdbc.Driver。使用原来的也不会报错,但是会输出一个提示。所以我做了修改。
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. 
The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
  • 需要添加useSSL=false&serverTimezone=UTC。不使用SSL,并设置时区。若不设置时区,会出现以下错误。
com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
  • MyBatis的type-aliases-package我设置的是POJO取别名。

5.创建Dao,UserMapper.java。

package com.cn.dao.mysql;

import com.cn.entities.mysql.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Mapper
@Component
public interface UserMapper {

    User fetchById(Object id);

    List<User> fetchList(Map<String, Object> query);

    int save(User user);

    int deleteById(Object id);

    int update(User user);

}

6.在resources资源文件目录下创建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">
<mapper namespace="com.cn.dao.mysql.UserMapper">

    <!--做返回结果映射,添加了resultMap之后,在select中就可以将resultMap指定为userResultMap,结果会映射为对象-->
    <resultMap id="userResultMap" type="User">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="password" column="password"/>
        <result property="identifyType" column="identify_type"/>
        <result property="identifyNumber" column="identify_number"/>
        <!--关联Department表,javaType中指定Department的类路径,property中是对象的属性-->
        <association property="department" javaType="com.cn.entities.mysql.Department">
            <!--此处的id指Department对象中的属性,dept_id是user表中的dept_id,关联字段-->
            <id property="id" column="dept_id"/>
            <result property="name" column="dept_name"/>
        </association>
    </resultMap>

    <sql id="select_statement">
        select
        u.id,
        u.name,
        u.password,
        u.identify_number,
        u.identify_type,
        u.dept_id,
        t.id,
        t.name dept_name
        from user u left join department t on u.dept_id = t.id
        where 1 = 1
    </sql>

    <select id="fetchById" parameterType="java.lang.Object" resultMap="userResultMap">
        <include refid="select_statement"/>
        and t.id = #{id}
    </select>

    <select id="fetchList" parameterType="java.util.HashMap" resultMap="userResultMap">
        <include refid="select_statement"/>
    </select>

    <insert id="save" parameterType="User">
        insert into user(name,password,identify_type,identify_number,dept_id)
        values(#{name},#{password},#{identifyType},#{identifyNumber},#{department.id})
    </insert>

    <update id="update" parameterType="User">
        update user
        <trim prefix="set" suffix="where id = #{id}" suffixOverrides=",">
            <if test="name != null">name=#{name},</if>
            <if test="password != null">password=#{password},</if>
            <if test="identifyType != null">identify_type=#{identifyType},</if>
            <if test="identifyNumber != null">identify_number=#{identifyNumber},</if>
            <if test="department.id != null">dept_id=#{department.id},</if>
        </trim>
    </update>

    <delete id="deleteById" parameterType="java.lang.Object">
        delete from user where id = #{id};
    </delete>

</mapper>

一句话总结,resultMap中property映射的是对象的属性,column映射的是sql语句中的列,若需要做对应,则需指定对应的列别名

6.创建service。IBaseService.java,BaseServiceImpl.java,IUserService.java,UserServiceImpl.java

package com.cn.service;

import java.util.List;
import java.util.Map;

public interface IBaseService<T> {
    public abstract T fetchById(Object id);

    public abstract List<T> fetchList(Map<String, Object> query);

    public abstract boolean save(T t);

    public abstract boolean update(T t);

    public abstract boolean deleteById(Object id);
}
package com.cn.service.impl;

import com.cn.service.IBaseService;

import java.util.List;
import java.util.Map;

public class BaseServiceImpl<T> implements IBaseService<T> {
    @Override
    public T fetchById(Object id) {
        return null;
    }

    @Override
    public boolean save(T t) {
        return false;
    }

    @Override
    public boolean deleteById(Object id) {
        return false;
    }

    @Override
    public List<T> fetchList(Map query) {
        return null;
    }

    @Override
    public boolean update(T t) {
        return false;
    }
}
package com.cn.service;

import com.cn.entities.mysql.User;

public interface IUserService extends IBaseService<User>{

}
package com.cn.service.impl;

import com.cn.dao.mysql.UserMapper;
import com.cn.entities.mysql.User;
import com.cn.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public User fetchById(Object id) {
        return userMapper.fetchById(id);
    }

    @Override
    public boolean save(User user) {
        try {
            userMapper.save(user);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean deleteById(Object id) {
        try {
            userMapper.deleteById(id);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public List<User> fetchList(Map query) {
        return userMapper.fetchList(query);
    }

    @Override
    public boolean update(User user) {
        try {
            userMapper.update(user);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}

7.启用MapperScan扫描dao,com.cn.dao.mysql为dao存放的包路径。

package com.cn;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@MapperScan("com.cn.dao.mysql")
@EnableScheduling
public class TissueDaoApplication {

    public static void main(String[] args) {
        SpringApplication.run(TissueDaoApplication.class, args);
    }

}

8.进行测试

src/test/java/com/cn/service目录下创建TestUserService.java进行测试。

package com.cn.service;

import com.cn.entities.mysql.Department;
import com.cn.entities.mysql.User;
import com.cn.util.Json;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestUserService {
    @Autowired
    private IUserService userService;

    @Test
    public void create(){
        User user = new User();
//      模拟数据库查询部门信息
        Department department = new Department();
        department.setId(4);
        department.setName("商品部");
        user.setDepartment(department);
        user.setName("张三");
        user.setPassword("123456");
        user.setIdentifyType(0);
        user.setIdentifyNumber("420612345678910001");
        userService.save(user);

    }

    @Test
    public void update(){
        User user = userService.fetchById(2);
        System.out.println(Json.toJson(user));
//      模拟数据库查询部门信息
        Department department = new Department();
        department.setId(4);
        department.setName("商品部");
        user.setDepartment(department);
        System.out.println(Json.toJson(user));
        userService.update(user);
    }

    @Test
    public void fetchById(){
        System.out.println(Json.toJson(userService.fetchById(1)));
    }
}

另外需要注意的是,个人建议在查询时最好是将所有的列展示出来,而不要用select *。在级联情况下具有同名字段时,最好另取别名。在查询条件中如果条件是级联表中同名字段,需要指定具体查询哪张表。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM