Spring Boot(3) Mybatis + Mapper

2017-08-30  本文已影响120人  科学Jia

你要搞清楚自己人生的剧本:不是你父母的续集,不是你子女的前传,更不是你朋友的外篇。对待生命你不妨大胆冒险一点,因为好歹你要失去它。
——尼采

Mybatis

以前做性能测试,需要把测试数据插入到测试数据库里,然后采用的就是最基本的JDBC的方式:

try {
            // 加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 通过驱动管理类获取数据库链接
            connection = DriverManager.getConnection(
                            "jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8",
                            "root", "root");
            // 定义sql语句 ?表示占位符
            String sql = "select * from t_user where username = ?";
            //获取预处理statement
            preparedStatement = connection.prepareStatement(sql);
            // 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
            preparedStatement.setString(1, "王五");
            // 向数据库发出sql执行查询,查询出结果集
            resultSet = preparedStatement.executeQuery();

但是,如果频繁的创建数据库连接和关闭,将会造成数据库性能上的瓶颈,网上也有解决方法,通过连接池管理数据库的连接。还有一个就是,把sql语句硬编码在代码里,也不便于维护。
Mybatis框架的出现就是为了更完美的操作数据库,用网上资料的话说:

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回

看到一个小姑娘在网上的绘图mybatis的原理图,觉得非常棒,放在这里。

mybatis原理图.png
具体的过程分析可以看她写的文章:
mybatis是什么?写的很好,推荐看看

Mapper

掌握了Mybatis这个神器以后,本来以为可以愉快的实现DAO接口了,结果又发现了一个叫Mapper接口的利器,可以做到跟DAO一样的事情,而且更简单。
DAO接口
如果我们用DAO的话,代码画风是这样的:

public interface UserDao {
    public UserInfo getUser(int id) throws Exception;
    //添加用户信息
    public void insertUser(UserInfo userInfo) throws Exception;
}

***DAO接口的实现****

public class UserDaoImpl implements UserDao{
    //需要向dao实现类中注入SqlSessionFactory
    //这里通过构造方法注入
    private SqlSessionFactory sqlSessionFactory;
    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        super();
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public User getUser() throws Exception {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        User user=sqlSession.selectOne("test.getUser", id);
        //释放资源
        sqlSession.close();
        return user;
    }

    @Override
    public void insertUser(UserInfo user) throws Exception {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        sqlSession.insert("test.insertUser", user);
        //提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
    }
}

可以看出,我们可以在DAO的实现类里提取出公共方法。

SqlSession sqlSession=sqlSessionFactory.openSession();
User user=sqlSession.selectOne("test.getUser", id);

SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser", user);

于是伟大的Mapper接口排上用处了。程序员只需要写mapper接口(相当于dao接口))就可以了。
它长这个样子,跟DAO接口一样,但不用写Mapper的实现了。

package com.siemens.springb.mapper;


import com.siemens.springb.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserInfoMapper {
    //根据具体的id查询user的信息
    List<UserInfo> getid(int id);

    //查询所有的消息
    List<UserInfo> getAll();

    //插入数据
    void insertUser(UserInfo userInfo);
}

重点来了!!!
如何把刚刚讲到的Mybatis,Mapper结合Spring Boot实现呢?
1、在Build.Gradle里把Mybatis Starter和MySQL的Driver配置好,我假设你的MySQL在本地或者其他地方已经装好了。(我开始没有配置MySQL的driver,导致项目启动后就报错)

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile('org.springframework.boot:spring-boot-starter-test')
    compile group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '1.1.1'
    compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'
}

顺便多说一句,如果你知道可能要引用的包,不知道Gradle怎么写,可以在Maven Repository里面找到Gradle的相关配置方法,这个好用。

image.png

2、创建xxxMapper.xml文件,路径在main/resource/mybatis/下面(mybatis文件夹是我自己手动创建的...)
我们来看看这个xxxMapper.xml文件,非常需要注意的是,这个namespace一定要指向Mapper接口。

<?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接口 -->
<mapper namespace="com.siemens.springb.mapper.UserInfoMapper">

    <!-- 所有列 -->
    <sql id="Column_list">
        user_id,
        user_name,
        user_score
    </sql>

    <resultMap id="ListTest" type="com.siemens.springb.model.UserInfo" >
        <id  column="user_id" property="id" />
        <result column="user_name" property="name" />
        <result column="user_score" property="score" />
    </resultMap>

    <!-- 根据ID查询数据 -->
    <select id="getid" parameterType="int" resultMap="ListTest">
        SELECT
        <include refid="Column_list" />
        FROM user_info WHERE user_id = #{id}
    </select>

    <!-- 查询所有的数据 -->
    <select id="getAll" resultMap="ListTest">
        SELECT
        <include refid="Column_list" />
        FROM user_info
    </select>

    <!-- 插入User数据 -->
    <select id="insertUser" parameterType="com.siemens.springb.model.UserInfo">
        INSERT INTO user_info (<include refid="Column_list" />)
        VALUES (#{id},#{name},#{score})
    </select>

</mapper>

3、在application.propertis里添加MySQL的配置信息,方便从数据库读写数据。
这里/dev_test是我在本地创建的一个数据库名称。

#server configuration
server.port = 8081
server.context-path = /AssetOnboard

#mysql config
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/dev_test?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.max-active=10
spring.datasource.max-idle=5
spring.datasource.min-idle=0

mybatis.mapper-locations=classpath:/mybatis/*.xml

4、创建Mapper接口。这样它就跟mybatis配置文件xxxMapper.xml里的namespace的值对应起来了,namespace = “com.siemens.springb.mapper.UserInfoMapper”。

package com.siemens.springb.mapper;


import com.siemens.springb.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserInfoMapper {
    //根据具体的id查询user的信息
    List<UserInfo> getid(int id);

    //查询所有的消息
    List<UserInfo> getAll();

    //插入数据
    void insertUser(UserInfo userInfo);
}

同时我们看到,getid(int id)、getAll() 和 insertUser(userInfo) 它们3个分别是对应xxxMapper.xml里的<select id="getid"...<select id="getAll"...<select id="insertUser"
对于需要传入参数的int id 和 UserInfo userInfo,在xml里面通过parameter=“int” 和 parameter="com.siemens.springb.model.UserInfo"指定类型。

5、创建POJO类UserInfo

package com.siemens.springb.model;

public class UserInfo {
    private int id;
    private String name;
    private float score;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setScore(float score) {
        this.score = score;
    }

    public float getScore() {
        return score;
    }
}

6、创建@Service: UserService,将UserInfoMapper接口通过@Autowired注入到Service。

package com.siemens.springb.service;

import com.siemens.springb.BeanWithoutProperties;
import com.siemens.springb.mapper.UserInfoMapper;
import com.siemens.springb.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    //UserInfoMapper注入到Service
    @Autowired
    UserInfoMapper userInfoMapper;

    //根据id返回特定的user信息
    public List<UserInfo> getUserInfo(int id){
        return userInfoMapper.getid(id);
    }

    //查询返回所有的用户信息
    public List<UserInfo> getAllUserInfo(){
        return userInfoMapper.getAll();
    }
    //插入user info的数据
    public void insertUser(UserInfo userInfo){
        userInfoMapper.insertUser(userInfo);
    }
}

7、再次通过@Autowired把@Service注入到Controller层

package com.siemens.springb;


import com.siemens.springb.model.UserInfo;
import com.siemens.springb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;

import java.util.List;


//表明这是一个 Controller
@Controller
//RestController是一种Rest风格的Controller,可以直接返回对象而不返回视图,返回的对象可以使JSON,XML等

public class SpringController {
    //Service注入到Controller
    @Autowired
    UserService userService;

       //mybatis取代简单原始的jdbc,mapper接口取代DAO接口编程,service注入到controller
    //根据传入的user_id参数来查询user_info表里指定ID的数据
    @RequestMapping("/getUser")
    //表示返回JSON格式的结果,如果前面使用的是@RestController可以不用写
    @ResponseBody
    public String getUsers(@RequestParam("user_id") Integer userId) {

        List<UserInfo> userInfo = userService.getUserInfo(userId);
        String note = "Note: " + "\n\t" + "mybatis把对数据库的操作进行了封装,取代原始简单的JDBC。 " + "\n\t";
        String userDetail = "";
        for(UserInfo info:userInfo){
            userDetail += "Name: " + info.getName() + " " + "ID: " + info.getId()+ " " +  "\n\t";
        }
        return note  + userDetail;
    }

    //查询user_info表里的所有的user信息
    @RequestMapping("/getAllUser")
    //表示返回JSON格式的结果,如果前面使用的是@RestController可以不用写
    @ResponseBody
    public Object getAllUsers() {
        List<UserInfo> userInfo = userService.getAllUserInfo();
        return userInfo;
    }

    //插入User Info数据到user_info表
    @RequestMapping("/upLoadUserInfo")
    //表示返回JSON格式的结果,如果前面使用的是@RestController可以不用写
    @ResponseBody
    public String upLoadInfo2UserInfo(@RequestParam("user_id") Integer userId,  @RequestParam("user_name") String username, float user_score) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(userId);
        userInfo.setName(username);
        userInfo.setScore(user_score);
        userService.insertUser(userInfo);
        return "Insert Success";
    }

}

8、开始测试下:

从mySql查询数据: /getUser?user_id=88 image.png
写入数据到mySql: /upLoadUserInfo/user_id=52&user_name=stevenJia&user_score=10.0
image.png

ToDo:

1、代码这里没有做异常的处理,也还没有相应的log日志记录。
2、增加Junit测试代码

总结下:

在Spring Boot里其实是不推荐使用导入xml配置的,boot加载了默认配置,适用于大多数场景,但不是说就不能导入xml,并且它同样提供了强大的mvc的配置和自定义的配置,后面可以研究下。

参考文献

Mybatis从Spring MVC到Spring Boot,请一定要看!
妹纸写的Mapper接口和DAO接口的区别,也非常不错!
GitHub上一个很简单的例子可以更好的认清Spring Boot + Mybatis + Mapper的用法

上一篇 下一篇

猜你喜欢

热点阅读