SpringBoot中Hibernate,Mybatis使用一点

2018-06-04  本文已影响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}
上一篇下一篇

猜你喜欢

热点阅读