配置数据源

在依赖于Spring boot的spring-boot-starter-data-jpa后,就会默认为你配置数据源,这些默认的数据源主要是内存数据库,如h2,hqldb和Derby等内存数据,有时候这些数据源不满足我们的需求,需要配置自己的数据源。

  1. 启动默认数据源,以h2为例
    只需在maven中加入它的依赖,如下代码所示:
<dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
</dependency>

这样就可以不使用任何配置数据库的情况下运行spring boot工程了。

  1. 配置自定义数据源,以MySQL为例
    首先配置依赖
<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<!-- 配置MySQL依赖-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<!-- 配置DBCP依赖-->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
		</dependency>

这样做还不够,还需要配置数据库相关信息才能连接到数据库,还要配置application.properties文件已达到配置数据源的效果

spring.datasource.url=jdbc:mysql://localhost:3306/chapter05?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
#指定数据库连接池的类型
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

指定数据库连接池的类型:POOL和DBCP,这里指定DBCP。

监测数据库连接池的类型

package com.springboot.chapter05.db;


import javax.sql.DataSource;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * 监测数据库连接池类型
 * @author Administrator
 *
 */
@Component
//实现spring bean生命周期接口ApplicationContextAware
public class DataSourceShow implements ApplicationContextAware {
	ApplicationContext applicationContext = null;
	//spring容器会自动调用这个方法,注入spring IOC容器
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// TODO Auto-generated method stub
		this.applicationContext = applicationContext;
		DataSource bean = applicationContext.getBean(DataSource.class);
		System.out.println(bean.getClass().getName());
	}
}
结果org.apache.commons.dbcp2.BasicDataSource

使用Jdbc Template操作数据库

用户pojo

package com.springboot.chapter05.pojo;

import com.springboot.chapter05.enumeration.SexEnum;
public class JDBCUser {
	private Integer id;
	private String user_name; 
	private SexEnum sex;//枚举
	private String note;
	//get和set方法
	@Override
	public String toString() {
		return "JDBCUser [id=" + id + ", user_name=" + user_name + ", sex=" + sex + ", note=" + note + "]";
	}
}

性别枚举类

package com.springboot.chapter05.enumeration;

public enum SexEnum {
	MALE(1,"男"),
	FEMALE(2,"女");
	
	private int id;
	private String name;
	SexEnum(int id,String name){
		this.id=id;
		this.name=name;
	}
	public static SexEnum getEnumById(int id) {
		for(SexEnum sex : SexEnum.values()) {
			if(sex.getId()==id) {
				return sex;
			}
		}
		return null;
	}
	//get和set方法
}

定义用户服务接口

package com.springboot.chapter05.service;

import java.util.List;

import com.springboot.chapter05.pojo.JDBCUser;

public interface JdbcTmplUserService {
	public JDBCUser getUser(Integer id);
	public List<JDBCUser> findUsers(String user_name,String note);
	public int insertUser(JDBCUser user);
	public int updateUser(JDBCUser user);
	public int deleteUser(Integer id);
}

实现用户接口

package com.springboot.chapter05.service.impl;

import java.sql.ResultSet;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import com.springboot.chapter05.enumeration.SexEnum;
import com.springboot.chapter05.pojo.JDBCUser;
import com.springboot.chapter05.service.JdbcTmplUserService;
@Service
public class JdbcTmplUserServiceImpl implements JdbcTmplUserService {
	@Autowired
	private JdbcTemplate jdbcTemplate = null;
	
	//获取映射关系
	private RowMapper<JDBCUser> getUserMapper(){
		RowMapper<JDBCUser> userRowMapper = (ResultSet rs,int rownum) ->{
			JDBCUser user = new JDBCUser();
			user.setId(rs.getInt("id"));
			user.setUser_name(rs.getString("user_name"));
			user.setNote(rs.getString("note"));
			int sexId = rs.getInt("sex");
			SexEnum sexEnum = SexEnum.getEnumById(sexId);
			user.setSex(sexEnum);
			return user;
		};
		return userRowMapper;
	}
	@Override
	public JDBCUser getUser(Integer id) {
		// TODO Auto-generated method stub
		String sql = "select id,user_name,sex,note from t_user where id = ?";
		Object[] params = new Object[]{id};
		JDBCUser user = jdbcTemplate.queryForObject(sql, params, getUserMapper());
		return user;
	}
	@Override
	public List<JDBCUser> findUsers(String user_name, String note) {
		// TODO Auto-generated method stub
		String sql = "select id,user_name,sex,note from t_user where user_name like concat('%',?,'%') and note like concat('%',?,'%')";
		Object[] params = new Object[] {user_name,note};
		List<JDBCUser> list = jdbcTemplate.query(sql, params, getUserMapper());
		return list;
	}
	@Override
	public int insertUser(JDBCUser user) {
		// TODO Auto-generated method stub
		String sql = "insert into t_user (user_name,sex,note) values (?,?,?)";
		int i = jdbcTemplate.update(sql, user.getUser_name(),user.getSex().getId(),user.getNote());
		return i;
	}
	@Override
	public int updateUser(JDBCUser user) {
		// TODO Auto-generated method stub
		String sql = "update t_user set user_name = ?,note = ? where id = ?";
		int i = jdbcTemplate.update(sql, user.getUser_name(),user.getNote(),user.getId());
		return i;
	}
	@Override
	public int deleteUser(Integer id) {
		// TODO Auto-generated method stub
		String sql = "delete from t_user where id = ?";
		int i = jdbcTemplate.update(sql, id);
		return i;
	}
}

对jdbctemplate的映射关系是需要自己去实现Rowmapper接口,这样就可以完成数据库数据到POJO对象的映射了。在getUserMapper中使用了lambda表达式。

使用JPA(Hibernate)操作数据

在maven中引入了spring-boot-starter-data-jpa,这样便能够使用JPA编程
定义用户POJO

package com.springboot.chapter05.pojo;

import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import com.springboot.chapter05.converter.SexConverter;
import com.springboot.chapter05.enumeration.SexEnum;
//标明是一个实体类
@Entity(name = "user")
//定义映射的表
@Table(name = "t_user")
public class JPAUser {
	@Id	//标明主键
	@GeneratedValue(strategy = GenerationType.IDENTITY)//注解策略,递增
	private Integer id;
	@Column(name = "user_name") //定义属性和表的映射关系,当属性名和数据库字段名相同时,就不需要定义
	private String userName; 
	@Convert(converter = SexConverter.class)	//定义转换器
	private SexEnum sex;
	private String note;
	//get和set方法
	@Override
	public String toString() {
		return "JPAUser [id=" + id + ", user_name=" + userName + ", sex=" + sex + ", note=" + note + "]";
	}
}

使用注解@Entity标明这是一个实体类,@Table配置的属性name指出它映射数据库的表,这样实体就映射到了对应的表上,@Id标注那个属性为表的键,注解@GeneratedValue则是可以配置采用何种策略生成注解,@Column使属性名称和数据库字段一一对应。这里性别需要特殊的转换,使用@Convert指定了SexConvert作为转换器

package com.springboot.chapter05.converter;

import javax.persistence.AttributeConverter;

import com.springboot.chapter05.enumeration.SexEnum;

public class SexConverter implements AttributeConverter<SexEnum, Integer> {
	//将枚举转换成数据库列
	@Override
	public Integer convertToDatabaseColumn(SexEnum attribute) {
		// TODO Auto-generated method stub
		return attribute.getId();
	}
	//将数据库列转换成枚举
	@Override
	public SexEnum convertToEntityAttribute(Integer dbData) {
		// TODO Auto-generated method stub
		return SexEnum.getEnumById(dbData);
	}
}

定义JPA接口扩展JpaRespository可以获得JPA提供的方法

package com.springboot.chapter05.dao;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.springboot.chapter05.pojo.JPAUser;
/**
 * 定义JpaRepository便可以获得JPA提供的事务管理的方法
 * @author Administrator
 *
 */
public interface JpaUserRepository extends JpaRepository<JPAUser, Integer>{
	/**
	 * 按照用户名称模糊查询
	 * @param userName
	 * @return
	 */
	List<JPAUser> findByUserNameLike(String userName);
	/**
	 * 根据主键ID查询
	 * @param id
	 * @return
	 */
	JPAUser getUserById(Integer id);
	/**
	 * 根据用户名或备注进行模糊查询
	 * @param user_name
	 * @param note
	 * @return
	 */
	List<JPAUser> findByUserNameLikeOrNoteLike(String userName,String note);
}
package com.springboot.chapter05.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.springboot.chapter05.dao.JpaUserRepository;
import com.springboot.chapter05.pojo.JPAUser;

@Controller
@RequestMapping("/jpa")
public class JPAUserController {
	@Autowired
	private JpaUserRepository jpaUserRepository;
	
	@RequestMapping("/getUser")
	@ResponseBody
	public JPAUser getUser (Integer id) {
		JPAUser jpaUser = jpaUserRepository.findById(id).get();
		return jpaUser;
	}
	
	@RequestMapping("/findAll")
	@ResponseBody
	public Map<String,Object> findAll (){
		List<JPAUser> list = this.jpaUserRepository.findAll();
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("success", list);
		return map;
	}
	@RequestMapping("/findByUserNameLike")
	@ResponseBody
	public List<JPAUser> findByUserNameLike(String userName){
		List<JPAUser> list = jpaUserRepository.findByUserNameLike("%"+userName+"%");
		return list;
	}
	@RequestMapping("/getUserById")
	@ResponseBody
	public JPAUser getUserById(Integer id){
		JPAUser jpaUser = jpaUserRepository.getUserById(id);
		return jpaUser; 
	}
	@RequestMapping("/findByUserNameLikeOrNoteLike")
	@ResponseBody
	public List<JPAUser> findByUserNameLikeOrNoteLike(String userName,String note){
		
		List<JPAUser> list = this.jpaUserRepository.findByUserNameLikeOrNoteLike("%"+userName+"%", "%"+note+"%");
		return list;
	}
}

配置springboot启动文件

//定义JPA接口扫描包路径
@EnableJpaRepositories(basePackages = "com.springboot.chapter05.dao")
//定义Bean扫描路径
@EntityScan(basePackages = "com.springboot.chapter05.pojo")

配置JPA属性

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

整合Mybatis

  1. 引入关于mybatis的starter
<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.1</version>
		</dependency>
  1. 定义pojo,指定别名
package com.springboot.chapter05.pojo;

import org.apache.ibatis.type.Alias;

import com.springboot.chapter05.enumeration.SexEnum;
@Alias(value = "user")	//mybatis指定别名
public class User {
	private Integer id;
	private String user_name; 
	private SexEnum sex;
	private String note;
	//get和set方法
	@Override
	public String toString() {
		return "JDBCUser [id=" + id + ", user_name=" + user_name + ", sex=" + sex + ", note=" + note + "]";
	}
}
  1. 类型转换
    在pojo中有一个枚举类型,需要通过typehandler进行类型转换
package com.springboot.chapter05.typeHandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import com.springboot.chapter05.enumeration.SexEnum;

//声明jdbcType为整型
@MappedJdbcTypes(JdbcType.INTEGER)
//声明javatype为SexEnum
@MappedTypes(value = SexEnum.class)
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {
	//通过列明获取性别
	@Override
	public SexEnum getNullableResult(ResultSet rs, String columnName) throws SQLException  {
		// TODO Auto-generated method stub
		int sex = rs.getInt(columnName);
		if(sex!=1&&sex!=2) {
			return null;
		}
		return SexEnum.getEnumById(sex);
	}
	//通过下标获取性别
	@Override
	public SexEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		// TODO Auto-generated method stub
		int sex = rs.getInt(columnIndex);
		if(sex!=1&&sex!=2) {
			return null;
		}
		return SexEnum.getEnumById(sex);
	}
	//通过存储过程获取性别
	@Override
	public SexEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		// TODO Auto-generated method stub
		int sex = cs.getInt(columnIndex);
		if(sex!=1&&sex!=2) {
			return null;
		}
		return SexEnum.getEnumById(sex);
	}
	//设置非空性别参数
	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, SexEnum sex, JdbcType jdbcType)
			throws SQLException {
		// TODO Auto-generated method stub
		ps.setInt(i, sex.getId());
	}
}
  1. 配置用户映射文件
<?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.springboot.chapter05.dao.MyBatisUserDao">
	<select id="getUser" parameterType="Integer" resultType="com.springboot.chapter05.pojo.User">
		select id,user_name,sex,note from t_user where id=#{id}
	</select>
</mapper>
  1. 定义mybatis操作接口
package com.springboot.chapter05.dao;

import org.springframework.stereotype.Repository;

import com.springboot.chapter05.pojo.User;
@Repository
public interface MyBatisUserDao {
	public User getUser(Integer id);
}
  1. 配置映射文件和扫描别名
#mybatis映射文件通配
mybatis.mapper-locations=classpath:com/springboot/chapter05/mapper/*.xml
#mybatis扫描别名包,和注解@Alias联用
mybatis.type-aliases-package=com.springboot.chapter05.pojo
#配置typeHandler的扫描包
mybatis.type-handlers-package=com.springboot.chapter05.typeHandler
  1. 在启动类中使用@MapperScan定义扫描
//定义mybatis扫描
@MapperScan(
		//指定扫描包
		basePackages = "com.springboot.chapter05.*",
		//指定sqlsessionfactory,如果sqlsessiontemplate存在,则作废
		sqlSessionFactoryRef = "sqlSessionFactory",
		//指定sqlsessiontemplate,如果sqlsessionfactory存在,则作废
		sqlSessionTemplateRef = "sqlSessionTemplate",
		annotationClass = Repository.class)

@MapperScan允许通过扫描加载mybatis的mapper。

  1. 拦截器配置
package com.springboot.chapter05.plugin;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
@Intercepts(
	@Signature(type = StatementHandler.class, args = { Connection.class,Integer.class }, method = "prepare")
)
public class MyPlugin implements Interceptor {
	Properties properties = null;
	//拦截方法逻辑
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("插件拦截方法**************");
		return invocation.proceed();
	}
	//生成mybatis拦截器对象
	@Override
	public Object plugin(Object target) {
		// TODO Auto-generated method stub
		return Plugin.wrap(target, this);
	}
	//设置插件属性
	@Override
	public void setProperties(Properties properties) {
		// TODO Auto-generated method stub
		this.properties = properties;
	}
}

在application.properties文件增加下面的配置

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

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<plugins>
		<plugin interceptor="com.springboot.chapter05.plugin.MyPlugin">
			<property name="key1" value="key1"/>
			<property name="key2" value="key2"/>
			<property name="key3" value="key3"/>
		</plugin>
	</plugins>
</configuration>

如果不使用配置文件,也可以使用编码的形式处理

public class Chapter05Application {
	@Autowired
	SqlSessionFactory sqlSessionFactory = null;
	public void initMyBatis() {
		//插件实例
		Interceptor interceptor = new MyPlugin();
		//设置插件属性
		Properties properties = new Properties();
		properties.setProperty("key1", "value1");
		properties.setProperty("key2", "value2");
		properties.setProperty("key3", "value3");
		interceptor.setProperties(properties);
		//在sqlsessionfactory中添加插件
		sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
	}
	public static void main(String[] args) {
		SpringApplication.run(Chapter05Application.class, args);
	}
}