深入浅出Spring Boot 2.x(五)

第5章 访问数据库

JDBC --> EJB --> Hibernate --> JPA

MyBatis:一个不屏蔽SQL且提供动态SQL、接口式编程和简易SQL绑定POJO的半自动化框架

Spring知道hiJdbcTemplate的数据库访问模式

5.1 配置数据源

依赖于spring-boot-starter-data-jpa后,会默认为配置数据源,这些默认的数据源主要是内存数据库,如h2、hqldb和Derby等内存数据

5.1.1 启动默认数据源

以h2为例


<dependency>
	<groupId>org.springframework.bootgroupId>
	<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
	<groupId>com.h2databasegroupId>
	<artifactId>h2artifactId>
	<scope>runtimescope>
dependency>

5.1.2 配置自定义数据源

以MySQL为例


<dependency>
	<groupId>mysqlgroupId>
	<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
	<groupId>org.springframework.bootgroupId>
	<artifactId>spring-boot-starter-jdbcartifactId>
dependency>

配置数据库相关信息

application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/chapter5
spring.datasource.username=root
spring.datasource.password=123456
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#最大等待连接中的数量,设0为没有限制
spring.datasource.tomcat.max-idle=10
#最大连接活动数
spring.datasource.tomcat.max-active=50
#最大等待毫秒数,单位为ms,超过时间会出错误信息
spring.datasource.tomcat.max-wait=10000
#数据库连接池初始化连接数
spring.datasource.tomcat.initial-size=5

使用第三方数据源(如DBCP)


<dependency>
	<groupId>org.apache.commonsgroupId>
	<artifactId>commons-dbcp2artifactId>
dependency>
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_chapter5
spring.datasource.username=root
spring.datasource.password=123456
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#指定数据库连接池的类型
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
#最大等待连接中的数量,设0为没有限制
spring.datasource.dbcp2.max-idle=10
#最大连接活动数
spring.datasource.dbcp2.max-total=50
#最大等待毫秒数,单位为ms,超过时间会出错误信息
spring.datasource.dbcp2.max-wait-millis=10000
#数据库连接池初始化连接数
spring.datasource.dbcp2.initial-size=5

5.2 使用JdbcTemplate操作数据库

// 用户服务接口
public interface JdbcTmplUserService {
	public User getUser(Long id);

	public List<User> findUsers(String userName, String note);

	public int insertUser(User user);

	public int updateUser(User user);

	public int deleteUser(Long id);
	
	public User getUser2(Long id);
	
	public User getUser3(Long id);
}
/**** imports ****/
@Service
public class JdbcTmplUserServiceImpl implements JdbcTmplUserService {
	@Autowired
	private JdbcTemplate jdbcTemplate = null;

	// 获取映射关系
	private RowMapper<User> getUserMapper() {
		// 使用Lambda表达式创建用户映射关系
		RowMapper<User> userRowMapper = (ResultSet rs, int rownum)->{
			User user = new User();
			user.setId(rs.getLong("id"));
			user.setUserName(rs.getString("user_name"));
			int sexId = rs.getInt("sex");
			SexEnum sex = SexEnum.getEnumById(sexId);
			user.setSex(sex);
			user.setNote(rs.getString("note"));
			return user;
		};
		return userRowMapper;
	}

	// 获取对象
	@Override
	public User getUser(Long id) {
		// 执行的SQL
		String sql = "select id, user_name, sex, note from t_user where id = ?";
		// 参数
		Object[] params = new Object[] {id};
		User user = jdbcTemplate.queryForObject(sql, params, getUserMapper());
		return user;
	}

	// 查询用户列表
	@Override
	public List<User> findUsers(String userName, String note) {
		// 执行的SQL
		String sql = "select id, user_name, sex, note from t_user " + "where user_name like concat('%', ?, '%') "
				+ "and note like concat('%', ?, '%')";
		// 参数
		Object[] params = new Object[] {userName, note};
		// 使用匿名类实现
		List<User> userList = jdbcTemplate.query(sql, params, getUserMapper());
		return userList;
	}

	// 插入数据库
	@Override
	public int insertUser(User user) {
		String sql = "insert into t_user (user_name, sex, note) values(? , ?, ?)";
		return jdbcTemplate.update(sql, user.getUserName(), user.getSex().getId(), user.getNote());
	}

	// 更新数据库
	@Override
	public int updateUser(User user) {
		// 执行的SQL
		String sql = "update t_user set user_name = ?, sex = ?, note = ?  " + " where id = ?";
		return jdbcTemplate.update(sql, user.getUserName(), user.getSex().getId(), user.getNote(), user.getId());
	}

	// 删除数据
	@Override
	public int deleteUser(Long id) {
		// 执行的SQL
		String sql = "delete from t_user where id = ?";
		return jdbcTemplate.update(sql, id);
	}
	
	public User getUser2(Long id) {
	    // 通过Lambda表达式使用StatementCallback
	    User result = this.jdbcTemplate.execute((Statement stmt) -> {
	        String sql1 = "select count(*) total from t_user where id= " + id;
	        ResultSet rs1 = stmt.executeQuery(sql1);
	        while(rs1.next()) {
	            int total = rs1.getInt("total");
	            System.out.println(total);
	        }
	        // 执行的SQL
	        String sql2 = "select id, user_name, sex, note from t_user"
	                + " where id = " + id;
	        ResultSet rs2 = stmt.executeQuery(sql2);
	        User user = null;
	        while (rs2.next()) {
	            int rowNum = rs2.getRow();
	            user = getUserMapper().mapRow(rs2, rowNum);
	        }
	        return user;
	    });
	    return result;
	}

	public User getUser3(Long id) {
	    // 通过Lambda表达式使用ConnectionCallback接口
	    return this.jdbcTemplate.execute((Connection conn) -> {
	        String sql1 = " select count(*) as total from t_user"
	                + " where id = ?";
	        PreparedStatement ps1 = conn.prepareStatement(sql1);
	        ps1.setLong(1, id);
	        ResultSet rs1 = ps1.executeQuery();
	        while (rs1.next()) {
	            System.out.println(rs1.getInt("total"));
	        }
	        String sql2 = " select id, user_name, sex, note from t_user "
	                + "where id = ?";
	        PreparedStatement ps2 = conn.prepareStatement(sql2);
	        ps2.setLong(1, id);
	        ResultSet rs2 = ps2.executeQuery();
	        User user = null;
	        while (rs2.next()) {
	            int rowNum = rs2.getRow();
	            user= getUserMapper().mapRow(rs2, rowNum);
	        }
	        return user;
	    });
	}
}
  • 对JdbcTemplate的映射关系需要开发者自己实现RowMapper的接口的,这样就可以完成数据库数据到POJO ( Plain Ordinary Java Object )对象的映射

    • Java 8及以上版本,可以使用Lambda表达式
    • 低版本声明类或者使用匿名类
  • 增删改查:主要是传递参数,然后执行SQL后返回影响数据库记录数

  • JdbcTemplate每调用一次便会生成一个数据库连接

    • List list = this.jdbcTemplate.query(sql1, rowMapper);
      this.jdbcTemplate.update(sql2);
      
    • 从表面上看,这两个SQL都在同一个逻辑完成,而实际从底层的角度来看,它们是使用不同的数据库连接完成的

      • 当JdbcTemplate执行query 方法时,会从数据库连接池分配一条数据库连接资源,当其执行完后,会关闭数据库连接;当执行u pdate时,它又从数据库连接池分配一条新的连接去执行SQL
  • 在一个连接里面执行多条SQL可以使用StatementCallback或者ConnectionCallback接口实现回调

    • 如getUser2,getUser3

5.3 使用JPA(Hibernate)操作数据

JPA(Java Persistence API,Java 持久化API),是定义了对象关系映射(ORM)以及实体对象持久化的标准接口,不局限于EJB 3.0,而是作为POJO持久化的标准规范,可以脱离容器独立运行、开发和测试,更加方便

5.3.1 概述

在Spring Boot中JPA是依靠Hibernate实现的

JPA所维护的核心是实体(Entity Bean),而它是通过一个持久化上下文(Persistence Context)来使用的

持久化上下文包含3个部分:

  • 对象关系映射(Object Relational Mapping,简称ORM, 或O/RM,或O/R映射)描述
    • JPA支持注解或XML两种形式的描述,在Spring Boot中主要通过注解实现
  • 实体操作API
    • 通过这节规范可以实现对实体对象的CRUD操作,来完成对象的持久化和查询
  • 查询语言
    • 约定了面向对象的查询语言JPQL(Java Persistence Query Language),通过这层关系可以实现比较灵活的查询

5.3.2 开发JPA

/**** imports ****/
// 标明是一个实体类
@Entity(name = "user")
// 定义映射的表
@Table(name = "t_user")
public class User {
	// 标明主键
	@Id
	// 主键策略,递增
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id = null;

	// 定义属性和表的映射关系
	@Column(name = "user_name")
	private String userName = null;

	private String note = null;

	// 定义转换器
	@Convert(converter = SexConverter.class)
	private SexEnum sex = null;

	public Long getId() {
		return id;
	}

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

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getNote() {
		return note;
	}

	public void setNote(String note) {
		this.note = note;
	}

	public SexEnum getSex() {
		return sex;
	}

	public void setSex(SexEnum sex) {
		this.sex = sex;
	}
}

@Entity:表明这是一个实体类

@Table:属性name支出映射数据库的表

@Id:标明属性为表的主键

@GeneratedValue:配置采取何种策略生成主键

@Column:与数据库表的字段对应

@Convert:指定转换器。定义从数据库读出的转换规则和从属性转换为数据库列的规则

/**** imports ****/
public class SexConverter implements AttributeConverter<SexEnum, Integer>{
    // 将枚举转换为数据库列
    @Override
    public Integer convertToDatabaseColumn(SexEnum sex) {
        return sex.getId();
    }

    // 将数据库列转换为枚举
    @Override
    public SexEnum convertToEntityAttribute(Integer id) {
        return SexEnum.getEnumById(id);
    }
}

JpaRepository接口:定义对应操作

深入浅出Spring Boot 2.x(五)_第1张图片

  • Repository
    • JPA最顶级的接口,没有定义任何方法
  • CrudRepository
    • 定义实体最基本的增删改的操作,功能性还不足够强大
  • PagingAndSortingRepository
    • 继承CrudRepository并且提供了分页和排序的功能
  • JpaRepository
    • 扩展了PagingAndSortingRepository、QueryByExampleExecutor接口,这样就可以拥有按例子(Example)查询的功能

一般而言,只需要定义JPA 接口扩展JpaRepository便可以获得JPA提供的方法

public interface JpaUserRepository extends JpaRepository<User, Long> {
}

配置JPA属性

#使用MySQL数据库方言
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
#打印数据库SQL
spring.jpa.show-sql=true
#选择Hibernate数据定义语言(DDL)策略为update
spring.jpa.hibernate.ddl-auto=update

有时可能需要更加灵活的查询

  • 使用JPA查询语言(JPQL)

    • 与Hibernate提供的HQL十分接近

    • 使用注解@Query标识语句

    • // from user中的user是代码中定义的实体类名称(@Entity注解的name属性),所以才能这样定义一条JPQL,提供给上层调用
      @Query("from user where user_name like concat('%', ?1, '%') " 
              + "and note like concat('', ?2, '%')")
      	public List<User> findUsers(String userName, String note);
      
  • 按照一定规则命名的方法

    • /**
      	 * 按用户名称模糊查询
      	 * @param userName 用户名
      	 * @return 用户列表
      	 */
      	List<User> findByUserNameLike(String userName);
      
      	/**
      	 * 根据主键查询
      	 * @param id -- 主键
      	 * @return 用户
      	 */
      	User getUserById(Long id);
      
      	/**
      	 * 按照用户名称或者备注进行模糊查询
      	 * @param userName 用户名
      	 * @param note 备注
      	 * @return 用户列表
      	 */
      	List<User> findByUserNameLikeOrNoteLike(String userName, String note);
      

JPA还提供了级联等内容

5.4 整合MyBatis框架

比JPA和Hibernate更为简单易用,也更灵活

5.4.1 MyBatis简介

官方定义:MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以对配置和原生Map使用简单的XML或注解,将接口和Java的POJO(Plain Old Java Object,普通的Java对象)映射成数据库中的记录

MyBatis 是基于一种SQL到POJO的模型,它需要我们提供SQL 、映射关系(XML 或者注解, 目前以XML为主)和POJO。但对于SQL和POJO的映射关系,提供了自动映射和驼峰映射等,使开发者的开发工作大大减少;由于没有屏蔽SQL,这对于追求高响应和l性能的互联网系统是十分重要的,因此可以尽可能地通过SQL去优化性能,也可以做少量的改变以适应灵活多变的互联网应用。与此同时, 它还能支持动态SQL,以适应需求的变化。这样一个灵动的、高性能的持久层框架就呈现在我们面前,这些很符合当前互联网的需要

配置文件包括两个大的部分:基础配置文件、映射文件

依赖包:

<dependency>
			<groupId>org.mybatis.spring.bootgroupId>
			<artifactId>mybatis-spring-boot-starterartifactId>
			<version>1.3.1version>
		dependency>

5.4.2 MyBatis的配置

MyBatis是一个基于SqlSessionFactory构建的框架。对于SqlSessionFactory 而言,它的作用是生成SqISession接口对象,这个接口对象是MyBatis操作的核心

在MyBatis-Spring的结合中甚至可以“擦除”SqISession对象,使其在代码中“消失”,这样做的意义是重大的,因为SqlSession是一个功能性的代码,“擦除”它之后,就剩下了业务代码,这样就可以使得代码更具可读性

因为SqlSessionFactory的作用是单一的,只是为了创建核心接口SqISession,所以在MyBatis应用的生命周期中理当只存在一个SqlSessionFactory对象,并且往往会使用单例模式。而构建SqlSessionFactory是通过配置类(Configuration)来完成的,因此mybatis-spring-boot-starter会给予我们在配置文件(application.properties进行Configuration配置的相关内容

深入浅出Spring Boot 2.x(五)_第2张图片

MyBatis可配置的内容:

  • properties(属性):属性文件在实际应用中一般采用Spring进行配置
  • settings(设置):将改变MyBatis的底层行为,可以配置映射规则,如自动映射和驼峰映射、执行器(Executor)类型、缓存等内容,比较复杂,具体配置项可参考MyBatis官方网站(http://www.mybatis.org/mybatis-3/zh/configuration.html#settings)
  • typeAliases(类型别名):因为使用类全限定名会比较长,所以MyBatis会对常用的类提供默认的别名,此外还允许通过typeAliases配置自定义的别名
  • typeHandlers(类型处理器): 这是MyBatis的重要配置之一,在MyBatis 写入和读取数据库的过程中对于不同类型的数据(对于Java是JavaType,对于数据库则是JdbcType)进行自定义转换,在大部分的情况下不需要使用自定义的typeHandler,因为MyBatis自身就已经定义了比较多的typeHandler, MyBatis会自动识别javaType巳和jdbcType,从而实现各种类型的转换。一般来说, typeHandler 的使用集中在枚举类型上
  • objectFactory(对象工厂):一个在MyBatis生成返回的POJO时会调用的工厂类。一般使用MyBatis默认提供的对象工厂类(DefaultObjectFactory)就可以
  • plugins( 插件):有时候也称为拦截器,是MyBatis最强大也是最危险的组件,它通过动态代理和责任链模式来完成,可以修改MyBatis底层的实现功能
  • environments(数据库环境): 可以配置数据库连接内容和事务。一般而言, 这些交由Spring托管
  • databaseldProvider(数据库厂商标识):允许MyBatis配置多类型数据库支持, 不常用
  • mappers(映射器):MyBatis最核心的组件,提供SQL和POJO映射关系, 是MyBatis开发的核心
@Alias(value = "user")// MyBatis指定别名
public class User {
    private Long id = null;
    private String userName = null;
    private String note = null;
    // 性别枚举,需要使用typeHandler进行转换
    private SexEnum sex = null;
    public User() {
    }
    /**** setter and getter ****/
}
// 性别typeHandler
/**** imports ****/
// 声明JdbcType为整形
@MappedJdbcTypes(JdbcType.INTEGER)
// 声明JavaType为SexEnum
@MappedTypes(value=SexEnum.class)
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {
    // 通过列名读取性别
    @Override
    public SexEnum getNullableResult(ResultSet rs, String col) throws SQLException {
        int sex = rs.getInt(col);
        if (sex != 1 && sex != 2) {
            return null;
        }
        return SexEnum.getEnumById(sex);
    }
    // 通过下标读取性别
    @Override
    public SexEnum getNullableResult(ResultSet rs, int idx) throws SQLException {
        int sex = rs.getInt(idx);
        if (sex != 1 && sex != 2) {
            return null;
        }
        return SexEnum.getEnumById(sex);
    }    
    // 通过存储过程读取性别
    @Override
    public SexEnum getNullableResult(CallableStatement cs, int idx) throws SQLException {
        int sex = cs.getInt(idx);
        if (sex != 1 && sex != 2) {
            return null;
        }
        return SexEnum.getEnumById(sex);
    }
    // 设置非空性别参数
    @Override
    public void setNonNullParameter(PreparedStatement ps, int idx, SexEnum sex, JdbcType jdbcType) throws SQLException {
        ps.setInt(idx, sex.getId());
    }
}

在MyBatis中对于typeHandler的要求是实现TypeHandler接口

为了更加方便也通过抽象类BaseTypeHandler实现了TypeHandler接口,所以这里直接继承抽象类BaseTypeHandler就可以

注解@MappedJdbcTypes声明JdbcType为数据库的整型,@MappedTypes声明JavaType为SexEnum,这样MyBatis就可据此对对应的数据类型进行转换

为了使这个POJO能够与数据库的数据对应,还需要提供一个映射文件


<?xml version="1.0" encoding="UTF-8">

<mapper namespace="com.springboot.chapter5 dao.MyBatisUserDao">
	<select id="getUser" parameterType="long" resultType="user">
		select id, user_name as userName, sex , note from t_user where id=#{id}
	select>
mapper>

mapper元素

  • namespace属性
    • 指定一个接口
  • select元素
    • 代表着一个查询语句
      • id 属性指代这条SQL
      • parameterType属性配置为long,表示是一个长整型(Long)参数
      • resultType指定返回值类型
        • 这里使用了user,这是一个别名,因为代码中我们己经有了指代,所以才能这样使用,也可以使用全限定名(com.springboot.chapter5.pojo.User)
        • SQL语句
          • 列名和POJO 的属性名是保持一致的
          • 请注意,数据库表中的字段名为user_name,而POJO的属名为userName, 这里的SQL是通过字段的别名(userName)来让它们保持一致的
          • 在默认的情况下,MyBatis会启动自动映射,将SQL中的列映射到POJO上;也可以启动驼峰映射,这样就可以不启用别名

为了启用这个映射,还需要一个接口(仅仅是一个接口,并不需要任何实现类)它就是mapper元素的namespace属性定义的MyBatisUserDao

/**** imports ****/
@Repository
public interface MyBatisUserDao {
	public User getUser(Long id);
}

注解@Repository

方法getUser和映射文件中定义的查询SQL的id保持一致,参数也是如此

对映射文件、POJO的别名和typeHandler进行配置

  • #配置映射文件和扫描别名
    #MaBatis映射文件统配
    mybatis.mapper-locations=classpath:com/springboot/chapter5/mapper/*.xml
    #MyBatis扫描别名文件,和注解@Alias连用
    mybatis.type-aliases-package=com.springboot.chapter5.pojo
    #配置typeHandler的扫描别
    mybatis.type-handlers-package=com.springboot.chapter5.typehandler
    #日志配置
    #logging.level.root=DEBUG
    #logging.level.org.springframework=DEBUG
    #logging.level.org.org.mybatis=DEBUG
    

5.4.3 Spring Boot整合MyBatis

  • MapperFactoryBean类

    • 针对一个接口配置

    • // 使用MapperFactoryBean装配MyBatis接口
      @Autowired
      SqlSessionFactory sqlSessionFactory = null;
      // 定义一个MyBatis的Mapper接口
      @Bean
      public MapperFactoryBean<MyBatisUserDao> initMyBatisUserDao() {
      	MapperFactoryBean<MyBatisUserDao> bean = new MapperFactoryBean<>();
      	bean.setMapperinterface(MyBatisUserDao.class);
      	bean.setSqlSessionFactory(sqlSessionFactory);
      	return bean ;
      }
      
    • // 使用MyBatis接口
      /**** imports ****/
      @Service
      public class MyBatisUserServiceImpl implements MyBatisUserService {
          @Autowired
          private MyBatisUserDao myBatisUserDao = null;
          
          @Override
          public User getUser(Long id) {
              return myBatisUserDao.getUser(id);
          }
      }
      
    • 因为在启动文件中装配了对应的接口,所以可以采用加粗的代码进行依赖注入,把接口注入应用中

  • MapperScannerConfigurer类

    • 扫描装配,也就是提供扫描装配MyBatis的接口到Spring IoC容器中

    • /***
       * 配置MyBatis接口扫描
       * @return 返回扫描器
       */
      @Bean
      public MapperScannerConfigurer mapperScannerConfig() {
      	//定义扫描器实例
      	MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
      	//加载SqlSessionFactory,Spring Boot会自动生产SqlSessionFactory实例
      	mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
      	//定义扫描的包
      	mapperScannerConfigurer.setBasePackage("com.springboot.chapter5.*");
      	//限定被标注@Repository的接口才被扫描
      	mapperScannerConfigurer.setAnnotationClass(Repository.class);
      	//通过继承某个接口限制扫描,一般使用不多
      	//mapperScannerConfigurer.setMarkerInterface(......);
      	return mapperScannerConfigurer;
      }
      
    • 使用MapperScannerConfigurer类定义了扫描的包,这样程序就会去扫描对应的包

    • 还使用了注解限制,限制被标注为@Repository,这样就可以防止在扫描中被错误装配

    • 也可以使用接口继承的关系限定,但现实中使用得不多,

  • 注解@MapperScan

    • 能够将MyBatis所需的对应接口扫描装配到Spring IoC容器中

    • /**** imports ****/
      //定义Spring Boot扫描包路径
      @SpringBootApplication(scanBasePackages = {"com.springboot.chapter5"})
      //定义JPA接口扫描包路径
      @EnableJpaRepositories(basePackages = "com.springboot.chapter5.dao")
      //定义实体Bean扫描包路径
      @EntityScan(basePackages = "com.springboot.chapter5.pojo")
      @MapperScan(
      	//指定扫描包
      	basePackages = "com.springboot.chapter5.*",
      	//指定SqlSessionFactory,如果sqlSessionTemplate被指定,则作废
      	sqlSessionFactoryRef = "sqlSessionFactory",
      	//指定sqlSessionTemplate,将忽略sqlSessionFactory的配置
      	sqlSessionTemplateRef = "sqlSessionTemplate", 
      	//markerInterface = Class.class,//限定扫描接口,不常用
      	annotationClass = Mapper.class
      )
      public class Chapter5Application {
          // ......
      }
      
    • @MapperScan允许通过扫描加载MyBaits的Mapper

    • 如果Spring Boot项目中不存在多个SqlSessionFactory(或者SqlSessionTemplate),那么完全可以不配置sqlSessionFactoryRef (或者sqlSessionTemplateRef) , 上述代码关于它们的配置是可有可无的,但是如果是存在多个时,就需要指定

    • 注意:sqISessionTemplateRef的优先权大于sqlSessionFactoryRef,也就是当两者都配置之后,系统会优先选择sqlSessionTemplateRef,
      而把sqISessionFactoryRef作废

    • 这里选择使用注解@Repository作为限定,这是一个Spring对持久层的注解,而事实上MyBatis也提供了一个对Mapper的注解@Mapper,可以二选其一

5.4.4 MyBatis的其他配置

MyBatis常用配置

#定义Mapper的XML路径
mybatis.mapper-locations=......
#定义别名扫描的包,需要与@Alias联合使用
mybatis.type-aliases-package=......
#MyBatis配置文件,当配置比较复杂的时候,可以使用它
mybatis.config-location=......
#配置MyBaits插件(拦截器)
mybatis.configuration.interceptors=......
#具体类需要与@MappedJdbcTypes联合使用
mybatis.type-handlers-package=......
#级联延迟加载属性配置
mybatis.configuration.aggressive-lazy-loading=......
#执行器(Executor),可以配置SIMPLE,REUSE,BATCH,默认为SIMPLE
mybatis.executor-type=......

Spring Boot集成MyBatis插件

/**** imports ****/
// 定义拦截签名
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class MyPlugin implements Interceptor {
	Properties properties = null;
	// 拦截方法逻辑
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		System.out.println("插件拦截方法......");
		return invocation.proceed();
	}
	// 生成MyBatis拦截器代理对象
	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}
	// 设置插件属性
	@Override
	public void setProperties(Properties properties) {
		this.properties = properties;
	}
}

通过application.properties文件配置到MyBatis的配置中

mybatis.config.location=classpath:mybatis/mybatis-config.xml



<configuration>
    <mappers>
        <mapper resource="com/springboot/chapter5/mapper/User_Mapper.xml"/>
    mappers>
configuration>

也可以用代码进行处理

// 使用代码配置MyBatis
/**** imports ****/
// 定义Spring Boot扫描包路径
@SpringBootApplication(scanBasePackages={"com.springboot.chapters"})
// 定义JPA接口扫描包路径
@EnableJpaRepositories(basePackages="co.springboot.chapter5.da o")
// 定义实体Bean扫描包路径
@EntityScan(basePackages="com.springboot.chapter5.pojo")
@MapperScan(
	// 指定扫描包
	basePackages="com.springboot .chapter5.*",
	annotationClass=Repository.class)
public class Chapter5Application {
	// SqlSessionFactory对象由Spring Boot自动配置生成
	@Autowired
	SqlSessionFactory sqlSessionFactory = null;
	// 启用Spring Bean 生命周期执行方法, 加入插件
	@PostConstruct
	publiC void initMyBatis() {
		// 插件实例
		Interceptor plugin = new MyPlugin();
		// 设置插件属性
		Properties properties = new Properties() ;
		properties.setProperty("keyl", "valuel");
		properties.setProperty("key2", "value2");
		properties.setProperty("key3", "value3");
		plugin.setProperties(properties);
		// 在sqlSessionFactory中添加插件
		sqlSessionFactory.getConfiguration() .addinterceptor(plugin);
    }
	// ......
}
  • SqlSessionFactory对象由Spring Boot自动配置得到的,这步不需要处理,可以直接将它注入进来
  • 采用注解@PostConstruct自定义初始化后的initMyBatis方法。在该方法中可以配置插件
  • 在增加插件前,调用插件的setProperties方法设置相关的属性,然后把插件放入到MyBatis 的机制中

你可能感兴趣的:(#读书笔记,spring,boot,spring,boot)