springBoot(五):SpringBoot中MyBatis

mybatis是一个比较好的orm框架,至少我比较喜欢使用 ,对比hibernate稍微复杂了一些,但是这种复杂让我们可以灵活的编写sql,是我们的开发灵活性大大增加,但是这样必须对sql必须特别熟悉,包括一些sql优化;只有这样我们才能做出性能给常出色的系统。

我们知道在spring MVC中使用mybatis,是比复杂的;我配置各种各样的配置文件,并且在mapper文件中还要逐个声明对象的映射关系。那么mybatis在springBoot会不会更简单一些呢,接下来我们一起来看一下吧:

mybatis-spring-boot-starter、

官方说明:MyBatis Spring-Boot-Starter will help you use MyBatis with Spring Boot
这是mubatis基于springBoot开发的一套解决方案,目的是在springBoot中更加简单的使用,mybatis-spring-boot-starter主要有两种解决方案,一种是使用注解解决一切问题,一种是简化后的老传统。

首先我们引入mybatis-spring-boot-starter的pom依赖

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

首先说我们使用最新版本的1.3.2版本,另外引入mybatis需要写上版本号(没办法,谁让咱们不是亲生的呢!!!)


下面我们来分别介绍两种开发模式

无配置文件注解版

那就让注解来搞定一切吧!

1. 完整的pom.xml文件

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
		<optional>true</optional>
		<scope>true</scope>
	</dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-jdbc</artifactId>
       </dependency>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
	</dependency>
	<dependency>
		<groupId>org.mybatis.spring.boot</groupId>
		<artifactId>mybatis-spring-boot-starter</artifactId>
		<version>1.3.2</version>
	</dependency>
</dependencies>

这是我完整的配置文件,可能有些其他的jar包,请忽略!!!

2. application.yml 添加相关配置

mybatis:
  type-aliases-package: com.neo.entity
spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8
    username: root
    password: admin

springBoot会自动加载这些配置,数据源会注入到sqlSessionFactory中,sqlSessionFactory会自动注入到Mapper中,我们只需要使用它就行啦。

在启动类中添加对mapper包扫描@MapperScan

@SpringBootApplication
@MapperScan("com.neo.mapper")
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

或者每个Mapper类上都添加@Mapper注解,两种方式,任选一种就行。

3. 开发Mapper

这是最总要的一步,我们会在Mapper接口中使用注解的方式写sql语句

public interface UserMapper {

    @Select("SELECT * FROM users")
    @Results(id = "resultMap", value = {
            @Result(property = "sex",  column = "sex", javaType = SexEnum.class),
            @Result(property = "userName", column = "user_name"),
            @Result(property = "userPwd", column = "user_pwd")
    })
    List<User> getAll();

    @Select("SELECT * FROM users WHERE id = #{id}")
    @ResultMap("resultMap")
    User getOne(Long id);

    @Insert("INSERT INTO users(name, age, sex, user_name, user_pwd) VALUES (#{name}, #{age}, #{sex}, #{userName}, #{userPwd})")
    void insert(User user);

    @Update("UPDATE users SET name=#{name}, user_name=#{userName} WHERE id =#{id}")
    void update(User user);

    @Delete("DELETE FROM users WHERE id = #{id}")
    void delete(Long id);
}

为了更接近生产我特地将user_name、user_pwd两个属性在数据库加了下划线和实体类属性名不一致,另外sex使用了枚举

  • @Select 是查询类的注解,所有的查询均使用这个
  • @Result 修饰返回的结果集,关联实体类属性和数据库字段一一对应,如果实体类属性和数据库属性名保持一致,就不需要这个属性来修饰。
  • @Insert 插入数据库使用,直接传入实体类会自动解析属性到对应的值
  • @Update 负责修改,也可以直接传入对象
  • @delete 负责删除

如果想了解详细的使用方式,请去看官方文档

上面我们只使用可#{value}取值,请不要误解${value}的用法:

// 使用#{value}直接将类型注入进去,字符串两边不需要写单引号
@Select("Select * from teacher where name = #{name}")
Teacher query(@Param("name") String name);

// 而使用$是将字符串取出来,类型需要自己掌握
@Select("Select * from teacher where name = '${name}'")
Teacher query(@Param("name") String name);
@RestController
public class MyController {

    @Autowired
    private UserMapper userMapper;

    @RequestMapping("query")
    public List<User> query(){
        return userMapper.getAll();
    }

    @RequestMapping("save")
    public void save(){
        UserMapper.insert(new User("aa", 12, SexEnum.GIRL, "123456", "123456");
        UserMapper.insert(new User("bb", 13, SexEnum.GIRL, "123456", "123456");
        UserMapper.insert(new User("cc", 15, SexEnum.BOY, "123456", "123456");
    }
}

下面会讲一些注解的详细用法,接下来我们先看使用mapper文件怎么使用吧:

简单Mapper文件开发

这种开放方式保留了mybatis-config.xml文件,和mapper.xml文件,不需要写dao类,直接映射到mapper接口中的方法;也就是说上面的注解的部分写到了mapper文件中。

1. 配置

pom.xml文件和之前完全相同。

application.yml如下:

mybatis:
  type-aliases-package: com.neo.entity
  # 添加配置文件和mapper文件的位置
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8
    username: root
    password: admin

mybatis-config.xml 配置

<configuration>
	<typeAliases>
		<typeAlias alias="Integer" type="java.lang.Integer" />
		<typeAlias alias="Long" type="java.lang.Long" />
		<typeAlias alias="HashMap" type="java.util.HashMap" />
		<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
		<typeAlias alias="ArrayList" type="java.util.ArrayList" />
		<typeAlias alias="LinkedList" type="java.util.LinkedList" />
	</typeAliases>
</configuration>

这个文件和以前在springMvc中使用的全局配置文件相同,其他配置项,自己去看官方文档。

2、添加User的映射文件

<mapper namespace="com.neo.mapper.UserMapper" >
    <resultMap id="BaseResultMap" type="com.neo.entity.UserEntity" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="userName" property="userName" jdbcType="VARCHAR" />
        <result column="passWord" property="passWord" jdbcType="VARCHAR" />
        <result column="user_sex" property="userSex" javaType="com.neo.enums.UserSexEnum"/>
        <result column="nick_name" property="nickName" jdbcType="VARCHAR" />
    </resultMap>
    
    <sql id="Base_Column_List" >
        id, userName, passWord, user_sex, nick_name
    </sql>

    <select id="getAll" resultMap="BaseResultMap"  >
       SELECT 
       <include refid="Base_Column_List" />
	   FROM users
    </select>

    <select id="getOne" parameterType="java.lang.Long" resultMap="BaseResultMap" >
        SELECT 
       <include refid="Base_Column_List" />
	   FROM users
	   WHERE id = #{id}
    </select>

    <insert id="insert" parameterType="com.neo.entity.UserEntity" >
       INSERT INTO 
       		users
       		(userName,passWord,user_sex) 
       	VALUES
       		(#{userName}, #{passWord}, #{userSex})
    </insert>
    
    <update id="update" parameterType="com.neo.entity.UserEntity" >
       UPDATE 
       		users 
       SET 
       	<if test="userName != null">userName = #{userName},</if>
       	<if test="passWord != null">passWord = #{passWord},</if>
       	nick_name = #{nickName}
       WHERE 
       		id = #{id}
    </update>
    
    <delete id="delete" parameterType="java.lang.Long" >
       DELETE FROM
       		 users 
       WHERE 
       		 id =#{id}
    </delete>
</mapper>

其实就是将刚才的注解全部写到xml中。

3、编写Mapper接口

public interface UserMapper {
	
	List<UserEntity> getAll();
	
	UserEntity getOne(Long id);

	void insert(UserEntity user);

	void update(UserEntity user);

	void delete(Long id);

}

注意啦!这里的mapper接口中的方法名称要和mapper.xml文件中标签的id属性完全对应起来。

4、使用

测试就和刚才的Controller中的代码相同

如何选择

两种模式各有特点,注解版适合简单快速开发,当多表连接查询的需求非常少时,越适合这种模式。

老的mapper.xml文件的方式适合大项目,可以灵活的书写sql,方便调整SQL,写起sql更潇洒;

那么不使用mapper.xml文件真的不能完成复杂语句查询吗?答案肯定是否定的,还是有解决方案的:

解决方案一

我们可以直接在注解中使用 <script> 标签;如下:

@Select({
    "<script>",
        "SELECT ",
        "p.product_id, p.name, p.value, p.type, p.create_date, u.user_id, u.name ",
        "FROM product p",
        "LEFT JOIN user u ON u.user_id=p.create_user",
        "<where> ",
        "<if test='name != null'>",
            "and name=#{product.name}",
        "</if> ",
        "<if test='value != null'>",
            "and value=#{product.value}",
        "</if> ",
        "</where> ",
    "<script>",
})
@ResultMap("resultMap")
List<Product> findListByUser(@Param("product") Product user);

当我们使用 <script> 标签将注解中的sql语句包围住以后,被包围的sql语句就可以使用和mapper.xml 中相同的语法了

这样是暂时解决了复杂的 mapper.xml 文件问题,但是这样写代码可读行下降了很多,可以说比 mapper.xml 文件还要糟糕

解决方案二

第一种方案中,sql语句的可读性变得很差;这里我们使用 mybatis@SelectProvider 注解,实现在方法中拼接sql,如下:

public interface UserMapper {

    @SelectProvider(type=UserMapper.class, method="createSql")
    @ResultMap("resultMap")
    List<Product> findListByUser(@Param("product") Product user);

    class UserProvider {
        public String createSql(Map<String, Product> param) {
            StringBuffer sql = new StringBuffer();
            sql.append("SELECT p.product_id, p.name, p.value, p.type, ");
            sql.append("p.create_date, u.user_id, u.name ");
            sql.append("FROM product p");
            sql.append("LEFT JOIN user u ON u.user_id=p.create_user");
            sql.append("WHERE 1=1 ");
            if(!StringUtils.isEmpty(param.get("product").getName())) {
                sql.append("and name=" + param.get("product").getName());
            }
            if(!StringUtils.isEmpty(param.get("product").getValue())) {
                sql.append("and value=" + param.get("product").getValue());
            }
            return sql.toString();
        }
    }
}

这里就简单展示一下,这里需要注意的事项有,这里不详细介绍:

  • @Param 注解的使用
  • 构造sql语句函数的参数问题
  • #{name} 这类参数参数的使用

注意,Provider注解有多种注解,包括 SelectProviderInsertProviderUpdateProviderDeleteProvider,分别代表增删改查操作,这里也不详细介绍。

解决方案三

上面那一种解决方案,虽然解决了大部分代码可读性,但是 sql 拼接起来还是比较复杂,可读性并没有达到最好

这里我们使用 mybatis 自带的 SQL 类,进行拼接sql,我们在修改上面的那一部分代码:

public interface UserMapper {

    @SelectProvider(type=UserMapper.class, method="createSql")
    @ResultMap("resultMap")
    List<Product> findListByUser(@Param("product") Product user);

    class UserProvider {

        public String createSql(Map<String, Product> param) {
            return  new SQL() {{
                SELECT("p.product_id, p.name, p.value, p.type, ");
                SELECT("p.create_date, u.user_id, u.name ");
                FROM("product p");
                LEFT_OUTER_JOIN("user u ON u.user_id=p.create_user")
                sql.append("WHERE 1=1 ");
                if(!StringUtils.isEmpty(param.get("product").getName())) {
                    WHERE("name=#{product.name}");
                }
                if(!StringUtils.isEmpty(param.get("product").getValue())) {
                    WHERE("and value=#{product.value}");
                }
            }}.toString();
        }
    }
}

SQL 这个类只是为我们提供了一个简单的sql拼装方法,具体使用方式,自己探索吧,不过不推荐上面的这种写法,因为双大括号,会让编译后的文件多处一个.class 文件,如果这样的操作过多,会是项目运行变慢哦,正常的写法自己探索吧,因为 SQL 这个类实现方式很简单,看一下源码,就懂了。

这里提一下:在mybatis之前的版本中,有使用 SqlBuilder,但是现在这个方法已经过时了,不再推荐使用;但是有一点比较坑的地方是,如果我们看 SqlBuilder的源码,会发现,官方只标记它过时的类,但是没有指出更好的实现方式;这个自己找还是比较难找的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值