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