美文网首页
SpringBoot中Hibernate,Mybatis使用一点

SpringBoot中Hibernate,Mybatis使用一点

作者: 小白小白啦 | 来源:发表于2018-06-04 13:18 被阅读1886次

    使用SpringBoot开发有段时间了,主要是是从慕课上面看的两个课程入门的2小时学会Spring BootSpring Boot进阶之Web进阶,然后还购买了廖师兄的一个付费课程SpringBoot微信点餐系统,然后就开始SpringBoot开发了。因为之前写的是PHP,对Java完全不了解,感觉写起来非常繁琐,尤其是数据库这一块,操作非常麻烦,对查询返回的结果都要建一个对象。因为跟着课程来的,所以刚开始用的是hibernate,但是后来用了mybatis就放弃了hibernate,因为hibernate虽然不用写SQL但是不灵活。其实文章标题取得不是很准确,Hibernate是JPA规范的实现,主要是JPA和MyBatis进行对比的。看完本篇,你即可使用mybatis进行简单的开发。

    Hibernate使用

    MySQL user表

    CREATE TABLE `user` (
      `user_id` int(11) NOT NULL AUTO_INCREMENT,
      `user_name` varchar(255) DEFAULT NULL COMMENT '用户姓名',
      `user_phone` varchar(255) DEFAULT NULL COMMENT '用户电话',
      `user_password` varchar(255) DEFAULT NULL COMMENT '用户密码',
      `user_type` tinyint(4) DEFAULT NULL COMMENT '用户注册类型',
      `an_ticket` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '安券',
      `integral` float NOT NULL DEFAULT '0' COMMENT '积分',
      `user_photo` varchar(255) DEFAULT NULL COMMENT '用户头像',
      `user_input_invitation` varchar(255) DEFAULT NULL COMMENT '用户输入的邀请码',
      `user_invitation` varchar(255) DEFAULT NULL COMMENT '用户自己生成的邀请码',
      `login_time` timestamp NULL DEFAULT NULL COMMENT '上次登录时间',
      `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
      PRIMARY KEY (`user_id`),
      UNIQUE KEY `user_phone` (`user_phone`) USING BTREE,
      UNIQUE KEY `user_name` (`user_name`) USING BTREE,
      KEY `user_type` (`user_type`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=50 DEFAULT CHARSET=utf8;
    

    上面是user表,需要建一个对应的Java对象

    import lombok.Data;
    import org.hibernate.annotations.DynamicUpdate;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import java.math.BigDecimal;
    import java.util.Date;
    
    /**
     * Create by fengguofei
     * Date: 2017/9/2
     * Time: 18:02
     */
    @Entity
    @Data
    @DynamicUpdate
    public class User {
        @Id
        @GeneratedValue
        private Integer userId;
        //用户姓名
        private String userName;
        //用户手机
        private String userPhone;
        //用户密码
        private String userPassword;
        //用户类型
        private Integer userType;
        //账户安券
        private BigDecimal anTicket;
        //账户积分
        private BigDecimal integral;
        //用户头像
        private String userPhoto;
        //用户填写的邀请码
        private String userInputInvitation;
        //用户自己生成的邀请码
        private String userInvitation;
        //用户上次登录时间
        private Date loginTime;
        //创建时间
        private Date createTime;
        //更新时间
        private Date updateTime;
    }
    

    上面是对应的Java对象,其中@Data是lombok插件,会自动帮你生成get,set,toString等常用的方法,非常方便。@Entity代表是数据库对象,供springboot扫描使用,@DynamicUpdate表示动态更新,主要是数据库中的updateTime会更新当对user表更新时。
    MySQL列名字使用下划线分割,对应的Java对象使用驼峰规则,当然你也可以不这样做,使用@Column注解对列进行说明,@Table注解对表进行说明。

    创建Repository对象

    import com.anbixuan.dataobject.User;
    import com.anbixuan.dto.interfaceMysqlData.LoginJudgeInterface;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.Query;
    import org.springframework.data.repository.query.Param;
    
    import java.util.List;
    
    /**
     * Create by fengguofei
     * Date: 2017/9/2
     * Time: 18:28
     */
    public interface UserRepository extends JpaRepository<User, Integer>{
    
        User findUserByUserPhone(String userPhone);
    
        User findUserByUserName(String userName);
    
        User findUserByUserInvitation(String invitation);
    
        User findUserByUserId(Integer userId);
    
        //根据用户的姓名,手机号码,邮箱来检测用户是否存在
        @Query(value = "select u.user_id,u.user_type, u.user_password\n" +
                "from `user` u,csoperson cp\n" +
                "where u.user_id = cp.user_id and (u.user_name=:userNameOrPhoneOrEmail or u.user_phone=:userNameOrPhoneOrEmail\n" +
                "or cp.csoperson_email = :userNameOrPhoneOrEmail)\n" +
                "UNION\n" +
                "select u.user_id,u.user_type, u.user_password\n" +
                "from `user` u,csocompany cc\n" +
                "where u.user_id = cc.user_id and (u.user_name=:userNameOrPhoneOrEmail or u.user_phone=:userNameOrPhoneOrEmail\n" +
                "or cc.csocompany_email = :userNameOrPhoneOrEmail)\n" +
                "UNION\n" +
                "select u.user_id,u.user_type, u.user_password\n" +
                "from `user` u,factor f\n" +
                "where u.user_id = f.user_id and (u.user_name=:userNameOrPhoneOrEmail or u.user_phone=:userNameOrPhoneOrEmail\n" +
                "or f.factor_email = :userNameOrPhoneOrEmail)\n" +
                "UNION\n" +
                "select u.user_id,u.user_type, u.user_password\n" +
                "from `user` u,producer p\n" +
                "where u.user_id = p.user_id and (u.user_name=:userNameOrPhoneOrEmail or u.user_phone=:userNameOrPhoneOrEmail\n" +
                "or p.producer_email = :userNameOrPhoneOrEmail)\n" +
                "UNION\n" +
                "select u.user_id,u.user_type, u.user_password\n" +
                "from `user` u,hospital h\n" +
                "where u.user_id = h.user_id and (u.user_name=:userNameOrPhoneOrEmail or u.user_phone=:userNameOrPhoneOrEmail\n" +
                "or h.hospital_email = :userNameOrPhoneOrEmail)",nativeQuery = true)
        List<LoginJudgeInterface> findUserByNameOrPhoneOrEmail(@Param("userNameOrPhoneOrEmail") String userNameOrPhoneOrEmail);
    }
    

    可以看到对数据库的查询十分方便,从函数的名字就能知道这个查询的意义。第一个查询是通过用户的手机号码、第二个查询是通过用户的名字,以此类推,其中可以使用@Query进行SQL编写,除此之外JPA还提供了像like、orderBy、Not、In等操作具体可以查看Spring Data JPA - Reference Documentation

    缺点

    这个缺点是我自己的观点,可能不是很准确,因为我也不是很精通这个。一般建表都是创建主键,如果数据量很多,再加上索引。像其他的什么触发器、函数、外键都不创建,这些都由编程实现。问题出现了,JPA的动态查询如果关联表的话,你的Java对应的实体必须要创建外键,也就是manytomany、manytoone这些东西。此外你的查询结果如果只是一个表中的部分字段,你还要创建一个接口,比如上面的findUserByNameOrPhoneOrEmail查询就创建了一个LoginJudgeInterface接口,如果我查询结果很多,那岂不是要创建一堆接口。对我来多有点头疼。我的想法就是MySQL就是一个主键加索引,我的实体对象就是单个表的对应,甚至不需要创建表的实体对应,没有那些外键,查询要支持动态查询,返回结果也要比较方便。这些mybatis都能做的很好。

    Mybatis

    需要在pom.xml中引入mybatis依赖

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.2.0</version>
    </dependency>
    

    在.yml配置文件中加一些配置

    mybatis:
      mapper-locations: classpath:mapper/*.xml
      configuration:
        call-setters-on-nulls: true
    

    配置的作用是表明.xml文件的位置,以及如果查询结果是null也要返回对应的字段

    还需要在对应的Application上面加上@MapperScan的注解 MapperScan.png 接下来就可以使用mybatis了。一般需要创建一个对应的Mapper接口,里面写上SQL操作,对应的具体操作既可以使用@Select注解,也可以使用.xml文件来写。举个例

    通过@Select注解

    import org.apache.ibatis.annotations.ResultType;
    import org.apache.ibatis.annotations.Select;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * Create by fengguofei
     * Date: 2018/5/11
     * Time: 14:43
     */
    public interface RoleMapper {
    
    
        @Select("select DISTINCT(ar.role_id) as `value`, ar.`name` as label from admin_role ar")
        @ResultType(List.class)
        List<Map<String, Object>> getRoleList();
    
        @Select("select DISTINCT(ar.role_id) as roleId, ar.`name`, ar.introd from admin_role ar")
        @ResultType(List.class)
        List<Map<String, Object>> getRoleIntrodList();
    
    }
    

    如果这个Mapper文件没有放到之前指定的目录下面,springboot是无法扫描到的,可以添加@Mapper注解进行扫描。
    通过xml

    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    import java.util.Map;
    
    /**角色权限设置
     * Create by fengguofei
     * Date: 2018/5/21
     * Time: 19:54
     */
    public interface RoleAuthSetMapper {
    
        /**
         * 获得角色列表
         * @return
         */
        List getRoleList();
    
        /**
         * 根据name获得菜单列表
         * @param roleName
         * @return
         */
        List getRoleListByName(@Param("roleName") String roleName);
    
        /**
         * 获得菜单权限列表
         * @return
         */
        List getMenuAuth();
    
        /**
         * 添加角色,批量插入数据库
         * @param roles
         */
        void addRole(List<Map<String, String>> roles);
    
        /**
         * 获得最大的role_id
         * @return
         */
        Integer getRoleIdMax();
    
        /**
         * 获得某个角色对应的权限菜单
         * @param roleId
         * @return
         */
        List getRoleMenuAuth(@Param("roleId") String roleId);
    
        /**
         * 删除指定role_id的角色
         * @param roleIds
         */
        void deleteRoles(List roleIds);
    }
    

    对应的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.xxx.dataobject.mapper.admin.RoleAuthSetMapper">
    
        <select id="getRoleList" resultType="java.util.Map">
            select distinct(ar.role_id) as roleId, ar.`name`, ar.introd
            from admin_role ar
        </select>
    
        <select id="getRoleListByName" parameterType="java.lang.String" resultType="java.util.Map">
            select distinct(ar.role_id) as roleId, ar.`name`, ar.introd
            from admin_role ar
            <where>
                <if test="roleName != &quot;-1&quot;">
                    and ar.name like '%${roleName}%'
                </if>
            </where>
        </select>
    
        <select id="getMenuAuth" resultType="java.util.Map">
            select am.`name` as menuName, am.menu_id as menuId,aa.authority_id as authorityId, aa.`name` as authorityName
            from admin_menu am, admin_authority aa
            where am.authority_id = aa.authority_id
        </select>
        
        <insert id="addRole" parameterType="java.util.ArrayList">
            insert into admin_role (role_id, `name`, introd, authority_id, change_by)
            VALUES
            <foreach collection="list" item="role" separator=",">
                (#{role.roleId}, #{role.roleName}, #{role.introd}, #{role.authorityId}, #{role.changeBy})
            </foreach>
        </insert>
        
        <select id="getRoleIdMax" resultType="java.lang.Integer">
            SELECT MAX(ar.role_id)
            from admin_role ar;
        </select>
    
        <select id="getRoleMenuAuth" resultType="java.util.Map">
            select ar.`name` as roleName, ar.introd, am.`name` as menuName, am.menu_id as menuId,aa.authority_id as authorityId, aa.`name` as authorityName
            from admin_menu am, admin_authority aa, admin_role ar
            where am.authority_id = aa.authority_id
            and ar.authority_id = am.authority_id
            and ar.role_id = ${roleId}
        </select>
        
        <delete id="deleteRoles" parameterType="java.util.List">
            delete from admin_role
            where role_id IN
            <foreach collection="list" item="roleId" open="(" separator="," close=")">
                #{roleId}
            </foreach>
        </delete>
    
    </mapper>
    

    .xml文件一定要放到之前设置的目录下面,其中namespace一定要指定具体的mapper文件,不然会报错。接下来说一下对应的增删改查、动态查询、like查询以及其他操作。

    增删改查

    插入一条数据

         /**
         * 插入一条敏感词数据
         * @param sensitiveMap
         */
        void insertSensitiveWord(Map<String, String> sensitiveMap);
    
       <insert id="insertSensitiveWord" parameterType="java.util.Map">
            INSERT admin_sensitive_word_dict(sensitive_word, remark, change_by)
            VALUE (#{word}, #{remark}, #{changeBy})
        </insert>
    

    批量插入数据

        /**
         * 添加角色,批量插入数据库
         * @param roles
         */
        void addRole(List<Map<String, String>> roles);
    
        <insert id="addRole" parameterType="java.util.ArrayList">
            insert into admin_role (role_id, `name`, introd, authority_id, change_by)
            VALUES
            <foreach collection="list" item="role" separator=",">
                (#{role.roleId}, #{role.roleName}, #{role.introd}, #{role.authorityId}, #{role.changeBy})
            </foreach>
        </insert>
    

    就是通过foreach进行循环,foreach的具体用法可以查看官网

    删除一条数据

        /**
         * 删除指定role_id的角色
         * @param roleId
         */
        void deleteRole(Integer roleId);
    
        <delete id="deleteRoles" parameterType="java.lang.Integer">
            delete from admin_role
            where role_id  = #{roleId}
        </delete>
    

    批量删除数据

        /**
         * 删除指定role_id的角色
         * @param roleIds
         */
        void deleteRoles(List roleIds);
    
        <delete id="deleteRoles" parameterType="java.util.List">
            delete from admin_role
            where role_id IN
            <foreach collection="list" item="roleId" open="(" separator="," close=")">
                #{roleId}
            </foreach>
        </delete>
    

    插入一条数据

         /**
         * 插入后台用户
         * @param adminMap
         */
        Integer insertAdminUser(Map adminMap);
    
        <insert id="insertAdminUser" parameterType="java.util.Map" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
            insert admin_user (`name`, `password`, role_id, phone,
            branch_id, picture, education, graduate_school, major, id_number,
            change_by)
            value  (#{name}, #{password}, #{role_id}, #{phone},
            #{branch_id}, #{picture}, #{education}, #{graduate_school}, #{major}, #{id_number},#{change_by})
    
            <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
                SELECT LAST_INSERT_ID() as id
            </selectKey>
        </insert>
    

    批量插入数据

        /**
         * 添加角色,批量插入数据库
         * @param roles
         */
        void addRole(List<Map<String, String>> roles);
    
        <insert id="addRole" parameterType="java.util.ArrayList">
            insert into admin_role (role_id, `name`, introd, authority_id, change_by)
            VALUES
            <foreach collection="list" item="role" separator=",">
                (#{role.roleId}, #{role.roleName}, #{role.introd}, #{role.authorityId}, #{role.changeBy})
            </foreach>
        </insert>
    

    更新一条数据

        /**
         * 更新后台用户
         * @param adminMap
         */
        void updateAdminUser(Map adminMap);
    
        <update id="updateAdminUser" parameterType="java.util.Map">
            update admin_user
            set `name` = #{userName}, role_id = #{role_id}, phone = #{phone},
            branch_id = #{branch_id}, education = #{education}, graduate_school = #{graduate_school},
            major = #{major}, id_number = #{idNumber},change_by = #{change_by}
            where id = #{userId}
        </update>
    

    动态查询

    动态返回字段

        /**
         * 动态返回查询字段
         * @param startDate
         * @param endDate
         * @param columns
         * @return
         */
        List<Map<String, Object>> getOffLineDateByColumnAll(String startDate,String endDate, String[] columns);
    
        <select id="getOffLineDateByColumnAll" resultType="java.util.HashMap" >
            select
            <foreach collection="arg2" item="column" open="" separator="," close="">
                ${column}
            </foreach>
            from slabdatarealtime
            where slabdatarealtime.SlabTime &gt;= #{arg0}
            and slabdatarealtime.SlabTime &lt;= #{arg1}
        </select>
    

    动态查询条件

    动态and

        /**
         *根据name获得后台用户列表
         * @param name
         * @return
         */
        Page getAdminUserByNameList(@Param("sname") String name);
    
        <select id="getAdminUserByNameList" parameterType="java.lang.String" resultType="java.util.HashMap">
            select DISTINCT(au.id) as userId, au.`name` as userName, ar.`name` as roleName,au.phone,ab.`name` as branchName,
            au.education, au.graduate_school, au.major, au.id_number as idNumber
            from admin_user au, admin_role ar, admin_branch ab
            where au.role_id = ar.role_id
            and au.branch_id = ab.id
            <if test="sname != &quot;-1&quot;">
                and (au.`name` like '%${sname}%' or ar.`name` like '%${sname}%')
            </if>
        </select>
    

    动态where

        /**
         * 根据name获得菜单列表
         * @param roleName
         * @return
         */
        List getRoleListByName(@Param("roleName") String roleName);
    
        <select id="getRoleListByName" parameterType="java.lang.String" resultType="java.util.Map">
             select distinct(ar.role_id) as roleId, ar.`name`, ar.introd
            from admin_role ar
            <where>
                <if test="roleName != &quot;-1&quot;">
                    ar.name like '%${roleName}%'
                </if>
            </where>
        </select>
    

    like

    mybatis中like有几种写法,在此列举一下,以供学习。

    通过bind

        <select id="getSensitiveWord" resultType="java.util.Map" parameterType="java.lang.String">
            select aswd.id, aswd.sensitive_word as word, aswd.remark
            from admin_sensitive_word_dict aswd
            <where>
                <if test="sensitive != null">
                    <bind name="sent" value="'%' + sensitive + '%'"></bind>
                    aswd.sensitive_word like #{sent}
                </if>
            </where>
        </select>
    

    通过concat

            <if test="date != null ">
                and td.create_time like CONCAT('%','${date}','%')
            </if>
    

    直接写

             <if test="roleName != &quot;-1&quot;">
                    ar.name like '%${roleName}%'
              </if>
    

    分页

    通过PageHelper进行分页
    引入依赖

            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>1.2.2</version>
            </dependency>
    

    配置

    /**
     * Create by fengguofei
     * Date: 2018/3/1
     * Time: 18:31
     */
    
    import com.github.pagehelper.PageHelper;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.Properties;
    
    @Configuration
    public class MybatisConfig {
        //配置mybatis的分页插件pageHelper
        @Bean
        public PageHelper pageHelper(){
            PageHelper pageHelper = new PageHelper();
            Properties properties = new Properties();
            properties.setProperty("offsetAsPageNum","true");
            properties.setProperty("rowBoundsWithCount","true");
            properties.setProperty("reasonable","true");
            properties.setProperty("dialect","mysql");    //配置mysql数据库的方言
    //        properties.setProperty("params","count=countSql");
            pageHelper.setProperties(properties);
            return pageHelper;
        }
    }
    

    接下来就可以使用了
    .mapper接口

        /**
         *根据name获得后台用户列表
         * @param name
         * @return
         */
        Page getAdminUserByNameList(@Param("sname") String name);
    

    .xml文件

        <select id="getAdminUserByNameList" parameterType="java.lang.String" resultType="java.util.HashMap">
            select DISTINCT(au.id) as userId, au.`name` as userName, ar.`name` as roleName,au.phone,ab.`name` as branchName,
            au.education, au.graduate_school, au.major, au.id_number as idNumber
            from admin_user au, admin_role ar, admin_branch ab
            where au.role_id = ar.role_id
            and au.branch_id = ab.id
            <if test="sname != &quot;-1&quot;">
                and (au.`name` like '%${sname}%' or ar.`name` like '%${sname}%')
            </if>
        </select>
    

    service层

    import com.github.pagehelper.PageInfo;
    /**
     * Create by fengguofei
     * Date: 2018/4/16
     * Time: 16:07
     */
    public interface AdminUserService {
        /**
         * 根据name获得后台用户列表
         * @param name
         * @param page
         * @param size
         * @return
         */
        PageInfo getAdminUserByNameList(String name, Integer page, Integer size);
    

    serviceImpl层

    import com.xxx.dataobject.mapper.admin.AdminUserMapper;
    import com.anbixuan.service.admin.AdminUserService;
    import com.github.pagehelper.Page;
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * Create by fengguofei
     * Date: 2018/4/16
     * Time: 16:09
     */
    @Service
    public class AdminUserServiceImpl implements AdminUserService {
    
        @Autowired
        private AdminUserMapper adminUserMapper;
    
        /**
         * 根据name获得后台用户
         * @param name
         * @param page
         * @param size
         * @return
         */
        @Override
        public PageInfo getAdminUserByNameList(String name, Integer page, Integer size) {
            PageHelper.startPage(page, size);
            Page<Map<String, Object>> result =  adminUserMapper.getAdminUserByNameList(name);
            return result.toPageInfo();
        }
    

    controller

        /**
         * @param name
         * @param page
         * @param size
         * @return
         */
        @GetMapping("/get/user/by/name")
        public ResultVO getUserByName(@RequestParam(value = "name", defaultValue = "-1") String name,
                                       @RequestParam(value = "page", defaultValue = "1") Integer page,
                                       @RequestParam(value = "size", defaultValue = "10") Integer size,
                                       HttpServletRequest request){
            PageInfo adminUser = adminUserService.getAdminUserByNameList(name, page, size);
            Map<String, Object> resultMap = new LinkedHashMap<>();
            resultMap.put("number", adminUser.getTotal());
            resultMap.put("currentPage", page);
            resultMap.put("data",adminUser.getList());
            return ResultVOUtil.success(resultMap);
        }
    

    其中ResultVO是自定义的返回json格式,大家可以不使用,直接返回也可以。

    特殊符号

    原符号       <        <=      >       >=       &        '        "
    替换符号    &lt;    &lt;=   &gt;    &gt;=   &amp;   &apos;  &quot;
    例如:sql如下:
    create_date_time &gt;= #{startTime}  and  create_date_time &lt;= #{endTime}
    

    相关文章

      网友评论

          本文标题:SpringBoot中Hibernate,Mybatis使用一点

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