avatar

SpringBoot数据访问

简介

对于数据访问层,无论是SQL还是NOSQL,SpringBoot默认采用整合Spring Data的方式进行统一处理,添加大量自动配置,屏蔽了很多设置。引入各种xxxTemplate,xxxRepository来简化我们对数据访问层的操作。对于我们来说只需要进行简单的设置即可。

整合基本JDBC与数据源

我们需要这两个包来进行jdbc和mysql的连接

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

然后我们需要编写配置文件:

spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://192.168.1.8:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.jdbc.Driver

默认使用org.apache.tomcat.jdbc.pool.DataSource作为数据源,数据源的相关配置都在DataSourceProperties里面
写一个测试类试试

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootDataJdbcApplicationTests {
@Autowired
DataSource dataSource;

@Test
public void contextLoads() {
System.out.println("数据源信息"+dataSource.getClass());
try
{
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}

DataSource、JdbcTemplate以及JDBC的关系

DataSource是什么

Data Source与数据库连接池简介
在说DataSource之前我们应该来看一个java利用jdbc连接数据库的原生例子

public class ExampleDatabase {
//定义MySQL的数据库驱动程序
public static final String DBDRIVER = "com.mysql.jdbc.Driver";
//定义MySQL数据库的连接地址
public static final String DBURL = "jdbc:mysql://localhost:3306/test";
//MySQL数据库的连接用户名
public static final String DBUSER = "root";
//MySQL数据库的连接密码
public static final String DBPASS = "root";
public static void main(String[] args) {
Connection con = null;
try {
//加载驱动程序
Class.forName(DBDRIVER);
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
//连接MySQL数据库时,要写上连接的用户名和密码
con = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
}
catch (SQLException e) {
e.printStackTrace();
}
System.out.println(con);
try {
//关闭数据库
con.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}

这里真正起作用的代码是获取Connection,这里的Connection是利用DriverManager.getConnection获取的,这样利用jdbc获取的方式可以连接数据库但是有一些缺点
1、直接使用DriverManager的这种形式,通常需要将驱动程序硬编码到项目中
2、DriverManager的getConnection方法获取的连接,是建立与数据库的连接,建立与数据库的连接是一项较耗资源的工作,频繁的进行数据库连接建立操作会产生较大的系统开销。
这样会很消耗性能,导致系统变慢。
所以为了解决这种问题,就是用数据库连接池的方式进行代替,连接的持有是消耗空间的,但是现在绝大多数场景下,磁盘空间并没有那么金贵,我们更关心的是性能,所以空间换取时间,连接池的逻辑被广泛应用。
所以就引出了数据源的概念:
一种很自然的方式就是提供一个薄层的封装,建立一个中间层,这个中间层将DriverManager生成的连接,组织到连接池中,然后从池中提供连接。

Data Source就是DriverManager的一种替代角色,对外呈现就类似于一个DriverManager,拥有对外提供连接的能力。
数据源作为DriverManager的替代者,用于获取数据库连接,你应该总是使用DataSource.
DataSource是应用程序与数据库连接的一个抽象的中间层,是一个接口。对于DataSource已经有了很多优秀的实现,其中较为突出的为Druid,建议使用,Druid不仅仅提供了连接池的功能还提供了其他比如监控等功能,非常强大。

JdbcTemplate是什么

使用jdbc时,每次都需要自己获取PreparedStatement,输入sql语句参数,关闭连接等操作。造成操作冗余。影响我们打代码的效率。有了JDBCTemplate以后就可以只写SQL语句就可以了。
JdbcTemplate是Spring的一部分,是对数据库的操作在jdbc的封装,处理了资源的建立和释放(不需要我们管理连接了),我们只需要提供SQL语句(不需要我们设置参数了)和提取结果(查询时候可以直接返回对应的实体类),使JDBC更加易于使用。JdbcTemplate使用spring的注入功能,把DataSource注册到JdbcTemplate之中。

小结

DataSource是用来代替DriverManager使用的,JdbcTemplate是完全屏蔽了jdbc,对外只需要写sql语句即可。他们只是在JDBC的基础上实现了一些功能,但是本质上还是使用JDBC来实现数据库连接。
DataSource:为了节省连接数据库带来的性能损耗
JdbcTemplate:是为了简化JDBC的使用步骤,简化操作。

数据源自动配置原理:

在SpringBoot自动配置类的jdbc下:

  • 参考DataSourceConfiguration,根据配置创建数据源,默认使用Tomcat连接池;可以使用spring.datasource.typs来进行自定义的数据源类型

    • SpringBoot支持的数据源类型有这么几个:org.apache.tomcat.jdbc.pool.DataSource,com.zaxxer.hikari.HikariDataSource,org.apache.commons.dbcp.BasicDataSource,org.apache.commons.dbcp2.BasicDataSource
    • 自定义的数据源调用方式
         
      /**
      * Generic DataSource configuration.
      */
      @ConditionalOnMissingBean(DataSource.class)
      @ConditionalOnProperty(name = "spring.datasource.type")
      static class Generic {

      @Bean
      public DataSource dataSource(DataSourceProperties properties) {
      //使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
      return properties.initializeDataSourceBuilder().build();
      }

      }
  • DataSourceInitializer: class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {}是ApplicationListener,一个监听器
    ​作用:
    1)、runSchemaScripts();运行建表语句;
    2)、runDataScripts();运行插入数据的sql语句;
    默认只需要将文件命名为:

    schema-*.sql、data-*.sql
    默认规则:schema.sql,schema-all.sql;
    可以使用
    schema:
    - classpath:department.sql
    指定位置
  • 操作数据库:自动配置了JdbcTemplate操作数据库,JdbcTemplateAutoConfiguration

    @Configuration
    @ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
    @ConditionalOnSingleCandidate(DataSource.class)
    @AutoConfigureAfter(DataSourceAutoConfiguration.class)
    public class JdbcTemplateAutoConfiguration {
    private final DataSource dataSource;

    public JdbcTemplateAutoConfiguration(DataSource dataSource) {
    this.dataSource = dataSource;
    }
    @Bean
    @Primary
    @ConditionalOnMissingBean(JdbcOperations.class)
    public JdbcTemplate jdbcTemplate() {
    return new JdbcTemplate(this.dataSource);
    }
    @Bean
    @Primary
    @ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
    public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
    return new NamedParameterJdbcTemplate(this.dataSource);
    }
    }

    使用方法:

    @Controller
    public class HelloController {
    @Autowired
    JdbcTemplate jdbcTemplate;
    @ResponseBody
    @GetMapping("/query")
    public Map<String,Object> map()
    {
    List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * FROM department");
    return maps.get(0);
    }
    }

    这样就可以将数据取出来了。

使用druid数据源

什么是druid

Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。Druid是阿里巴巴开发的号称为监控而生的数据库连接池!

druid功能

  • 替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
  • 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
  • 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
  • SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
  • 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。

所以driud可以用来1、充当数据库连接池。2、可以监控数据库访问性能 3、获得SQL执行日志

SpringBoot整合

1、从maven官网找到druid的maven的配置

<!-- 引入druid数据源-->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>

2、配置文件指定数据源

spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://192.168.1.8:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource # 这里就是切换成driud数据源了。

3、druid属性设置
在dataSource后继续添加属性

#   数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

注意这里配置以后是不生效的,因为这不是SpringBoot提供的属性,需要我们自己去进行配置和设置

@Configuration
public class DruidConfig {

@ConfigurationProperties(prefix = "spring.datasource")//将配置文件中的配置映射到
@Bean//加入SpringBoot容器中
public DataSource druid()
{
return new DruidDataSource();//这样就把配置都添加进了数据源中
}
}

4、配置druid后端监控
还是在DtuidConfig类中继续编写

//配置Druid的监控
//1、配置一个管理后台的servlet
@Bean//将Servlet添加进去
public ServletRegistrationBean statViewServlet()
{
ServletRegistrationBean bean =new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String,String> initParams = new HashMap<>();
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");//不写默认是全部
bean.setInitParameters(initParams);
return bean;
}

//2、配置一个监控的filter
@Bean
public FilterRegistrationBean webStatFilter()
{
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");//这些请求不拦截
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}

5、看是都配置完成
我们启动应用,然后在浏览器输入loaclhost:8080/druid就可以进入druid的后台监控页面,输入在servley配置好的用户名密码,就可以登陆访问数据库连接请求了。

整合MyBatis

如果想要在项目中引入mtbatis,需要在pom文件中加入以下依赖

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
这是mybatis的依赖关系

MyBatis注解版使用

Mybatis注解的方式使用:

//指定这是一个操作数据库的mapper
@Mapper
public interface DepartmentMapper {

@Select("select * from department where id = #{id}")
public Department getDeptById(Integer id);

@Delete("ddelete from department where id=#{id}")
public int deleteDeptById(Integer id);

@Options(useGeneratedKeys = true,keyProperty = "id")//设置自增主键
@Insert("insert into department(departmentName) values(#{departmentName})" )
public int insertDept(Department department);

@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department)
}

这样我们直接在controller直接调用就可以查出数据了


@RestController
public class DeptController {
@Autowired
DepartmentMapper departmentMapper;

@GetMapping("/dept/{id}")
public Department getDept(@PathVariable("id") Integer id)
{
return departmentMapper.getDeptById(id);
}

@GetMapping("/dept")
public Department insertDept(Department department)
{
departmentMapper.insertDept(department);
return department;
}
}

注解版不需要配置是因为SpringBoot已经进行了自动配置在MybatisAutoConfiguration类中,类中有很多配置信息
自定义MyBatis的配置规则;给容器中添加一个ConfigurationCustomizer;


private final MybatisProperties properties;//所有的配置信息在这里面,想配置直接在配置文件中进行配置
private void applyConfiguration(SqlSessionFactoryBean factory) {
Configuration configuration = this.properties.getConfiguration();
if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
configuration = new Configuration();
}
if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);//获取所有的定制类,加到SqlSessionFactory中
}
}
factory.setConfiguration(configuration);
}

所以我们修改配置文件又两种方式
1、直接在配置文件中修改

mybatis:
configuration:
map-underscore-to-camel-case: true

2、写配置类实现配置方法

@org.springframework.context.annotation.Configuration
public class MyBatisConfig {

@Bean
public ConfigurationCustomizer configurationCustomizer()
{
return new ConfigurationCustomizer()
{
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}

如果我们的mapper很多,如果一个一个加就很费劲,所以我们需要进行整个mapper的扫描,需要给springboot主程序或者Mtbatis配置类加一个注解

//使用MapperScan批量扫描所有的Mapper接口;
@MapperScan(value = "com.zenshin.springbootmybatis.mapper")
@SpringBootApplication
public class SpringbootMybatisApplication {

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

}

MyBatis配置文件使用

如何使用mybatis(普通使用)

  • 需要编写一个mapper,来操作我们的实体

    @Mapper
    public interface EmployeeMapper {
    public Employee getEmpById(Integer id);

    public void insertEmp(Employee employee);
    }
  • 我们需要在资源文件中创建一个全局配置文件和mapper对应的sql文件,MyBatis官方文档

    <!--全局配置文件-->
    <?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>
    <!--这里可以采用官方的文档-->
    </configuration>


    <!--对应操作mapper的配置文件-->
    <?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.zenshin.springbootmybatis.mapper.EmployeeMapper">
    <!-- public Employee getEmpById(Integer id);

    public void insertEmp(Employee employee);用配置的方法实现sql-->

    <select id="getEmpById" resultType="com.zenshin.springbootmybatis.bean.Employee">
    SELECT * from employee where id=#{id}
    </select>

    <insert id="insertEmp">
    insert into employee(lastName,email,gender,d_id) values (#{lastName},#{email},#{gender},#{d_id})
    </insert>
    </mapper>
  • 需要在springboot的配置文件中添加文件路径

    mybatis:
    config-location: classpath:mybatis/mybatis-config.xml #主配置文件
    mapper-locations: classpath:mybatis/mapper/*.xml # 这样就把所有的mapper添加进来了
  • 写一个controller测试一下

    @RestController
    public class EmployeeController {
    @Autowired
    EmployeeMapper employeeMapper;

    @GetMapping("/emp/{id}")
    public Employee getEmp (@PathVariable("id") Integer id)
    {
    return employeeMapper.getEmpById(id);
    }
    }
  • 浏览器访问如果能获取到数据就成功了。

整合JPA

JPA是什么?

JPA (Java Persistence API)Java持久化API。是一套Sun公司Java官方制定的ORM 方案,是规范,是标准,sun公司自己并没有实现

JPA的实现者

既然我们说JPA是一套标准,意味着,它只是一套实现ORM理论的接口。没有实现的代码。 那么我们必须要有具体的实现者才可以完成ORM操作功能的实现! 市场上的主流的JPA框架(实现者)有:
Hibernate (JBoos)、EclipseTop(Eclipse社区)、OpenJPA (Apache基金会)。
其中Hibernate是众多实现者之中,性能最好的。
提醒:学习一个JPA框架,其他的框架都是一样使用

Spring Data

Spring Data项目的目的是为了简化构建基于Spring框架应用的数据访问技术,包括非关系型数据库、Map-Reduce框架,云数据服务登费等,同时也包含对关系型数据库的访问支持

Spring Data特点

Spring Data为我们提供使用统一的API来对数据访问层进行操作;这主要是Spring Data Commons项目来实现的。Spring Data Commons让我们在使用关系型或者非关系型数据库访问技术时都基于Spring提供的统一操作标准,标准包括了CRUD(创建,获取,更新,删除)、查询、排序和分页的相关操作

统一的Repository接口

Repository<T,ID extends Serializable>:统一接口
RevisionRepository<T,ID extends Serializable,N extends Number & Comparable>:基于乐观锁机制
CrudRepository<T,ID extends Serializable>:基于CRUD操作
PagingAndSortingRepository<T,ID extends Serializable>:基本CRUD以及分页

提供数据访问模板类

提供操作数据库的模板类如:MongoTemplate,RedisTemplate等

JPA与Spring Data

  • JpaRepository基本功能:编写接口继承JpaRepository 能够实现crud和分页等基本功能
  • 定义符合规范的方法命名:在接口中只需要声明符合规范的方法,即拥有对应的功能JPA命名规范
  • @Query自定义查询:定制查询sql
  • Specifications查询(Spring data JPA支持JPA2.0的Criteria查询)

SpringBoot整合JPA

1、我们可以用Spring的初始化器来实现,他在Maven中添加了这些

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

直接引入JPA即可,如果还要实现mysql的连接,还需要添加mysql的驱动,但是不需要jdbc了,JPA已经依赖了,并且Spring data JPA已经默认使用了hibernate作为JPA的实现。
2、然后我们配置数据源的相关属性

spring:
datasource:
username: root
password: 123456
type: org.apache.tomcat.jdbc.pool.DataSource
url: jdbc:mysql://192.168.1.8:3306/jdbc
driver-class-name: com.mysql.jdbc.Driver

这样以后就已经把所有的东西引入了,剩下的就是写代码来实现了

使用代码使用Spring Data JPA操作数据库

1、编写一个实体类(bean)和数据表进行映射,并且配置好映射关系;

//使用JPA注解配置映射关系
@Entity//告诉JPA这是一个实体类型(和数据表映射的类)
@Table(name = "tb1_user") //@Table来指定和哪个数据表对应;如果省略默认表名就是user:
public class User {
@Id//这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//主键自增
private Integer id;

@Column(name = "last_name",length = 50)//这是和数据表对应的一个列
private String lastName;

@Column//省略默认列名就是属性名
private String email;

public Integer getId() {
return id;
}

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

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}

2、编写一个Dao接口来操作实体类对应的数据表(Repository)

//继承JpaRepository来完成对数据库的操作
public interface UserRepository extends JpaRepository<User,Integer> {

}

3、基本的配置:JpaProperties类中有全部的定义

jpa:
hibernate:
# 更新或者创建数据表结构
ddl-auto: update
# 将所有的sql显示出来
show-sql: true

4、启动应用,JPA会帮我们把没有的表创建出来,然后就可以正常运行了。

5、进行增删改查的使用

@RestController
public class UserController {
@Autowired
UserRepository userRepository; //这里使用到的接口,其实现已经在hibernate中实现了,我们不需要做什么其他的处理

@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Integer id)
{
User user = userRepository.findOne(id);
return user;
}
@GetMapping("/user")
public User insterUser(User user)
{
User save = userRepository.save(user);
return save;
}
}

这样就可以直接进行使用了。

Mybatis多数据源实现

这里有一个非常重要的类AbstractRoutingDataSource,该类用于产生DataSource, 里面存放着多个数据源对象。
同时配合ThreadLocal,对于同一线程的使用同一个数据源

文章作者: zenshin
文章链接: https://zlh.giserhub.com/2020/04/20/springboot/data/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 zenshin's blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论