美文网首页
Spring Boot(3) Mybatis + Mapper

Spring Boot(3) Mybatis + Mapper

作者: 科学Jia | 来源:发表于2017-08-30 22:22 被阅读120次

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

    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的用法

    相关文章

      网友评论

          本文标题:Spring Boot(3) Mybatis + Mapper

          本文链接:https://www.haomeiwen.com/subject/qwgxjxtx.html