Spring中JDBC的使用

写在最前

现在已经JDBC封装的比较完善了,本篇也只是洒洒水的水平。也就是怎么用的水平。但是原理方面的东西还是需要查阅相关资料和书籍。而且,这篇会用之后,并没有什么卵用。只是知道后面封装对象大概的思路是什么。现实工程中还是很少会见到。

JdbcTemplate的起源

JDBC作为Java平台访问关系数据库的标准API,其成功是有目共睹的。几乎所有Java平台的数据访问,都直接地或者间接地使用了JDBC,它是整个Java平台面向关系数据库进行数据访问的基石。

作为一个标准,无疑JDBC是成功的。但是要说JDBC在实际的使用过程中也是受人欢迎的,则不尽然了。JDBC标准 主要面向较为底层的数据库操作,所以在设计过程中,比较贴近底层以提供尽可能多的功能特色。从这个角度来说,JDBC API的设计无可厚非。可是,过于贴近底层的API设计,对于开发人员的使用来说就不- -定是好事了。即使执行简单的查询或者更新,开发人员也要按照API的规矩写上一大堆雷同的代码。如果不能合理封装使用JDBC API的代码,在项目中使用JDBC访问数据所出现的问题估计会让人抓狂。

为了解决JDBC API在实际使用中的尴尬局面,Spring提出了JdbcTemplate作为数据访问的Helper类。这样处理之后,JDBC代码的使用得到了规范(进行数据访问的时候,每次使用的JDBC代码都几乎相同),异常处理和连接释放等问题也得到了统一的管理。

可以大致看一下源码,不过当然没这么简单。。。只是一个大概的样子

image-20200513102124913.png

image-20200513102142454.png

JdbcTemplate的使用

书上讲了很多相关的东西足足有一百页,但是总不可能照着字典学语文吧。下面记录的是常用的。

首先还是先引包

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>

然后在配置文件中配置

<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>


<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>

然后就可以在代码中调用

保存的操作(指查询的返回值为空的)

public class JdbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.获取 Spring 容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.根据 id 获取 bean 对象
        JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
        //保存
        jt.update("insert into account(name,money)values(?,?)","chayedan",5000);
    }
}

根据ID查询(指返回值为一行的),主要注意返回的封装容器为AccountRowMapper()对象

public class JdbcTemplateDemo2 {
    public static void main(String[] args) {
        //1.获取 Spring 容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.根据 id 获取 bean 对象
        JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
        //查询一个
        Account account = jt.queryForObject("select * from account where id = ? ",new BeanPropertyRowMapper<>(Account.class),1);        
        System.out.println(account);
    }
}

查询所有操作(返回值为多个)

public class JdbcTemplateDemo3 {
    public static void main(String[] args) {
        //1.获取 Spring 容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.根据 id 获取 bean 对象
        JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //3.执行操作
        //查询所有
        List<Account> accounts = jt.query("select * from account where money > ? ",new BeanPropertyRowMapper<>(Account.class), 500);
        for(Account account : accounts){
            System.out.println(account);
        }
    }
}

事务控制

Spring 中事务控制的 API

PlatformTransactionManager:此接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。

包含有3个具体的操作
TransactionStatus getTransaction(TransactionDefinition definition):获取事务状态信息
void commit(TransactionStatus status):提交事务
void rollback(TransactionStatus status):回滚事务

不过我们一般使用的是这个实现类

org.springframework.jdbc.datasource.DataSourceTransactionManager 用于Spring JDBC 或者 iBatis 进行持久化数据

另外一点

TransactionDefinitionTransactionStatus太庞杂了,详情请谷歌。

引包

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>

用XML 进行事务控制

在Spring的配置文件中配置

<!--
    配置事务管理器对象,传入DataSource对象
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--
        advice标签:需要把transactionManager对象
        由它使用transactionManage完成事务的环绕加强
    -->
<tx:advice id="transactionTX" transaction-manager="transactionManager">
        <!--
            细化的控制
            name 感兴趣的方法名,支持通配符
            read-only:是否是只读事务
            isolation:隔离级别
            timeout:超时时间 默认-1
            rollback-for: 捕获到该类型异常才回滚,默认只要捕获异常就回滚
            no-rollback-for  遇到该异常不回滚的类
            下面配置的意思就是只要不是以find开头的方法,都需要事务
        -->
        <tx:attributes>
            <tx:method name="*" read-only="false"  />
            <tx:method name="find*" read-only="true" isolation="DEFAULT" timeout="-1"  />
        </tx:attributes>
</tx:advice>
<!--配合上面的tx:advice标签使用-->
<aop:config>
        <aop:advisor advice-ref="transactionTX" pointcut="execution(* com.service..*.*(..))"></aop:advisor>

</aop:config>

说白了,就是利用AOP来进行事务控制

但是太复杂了,推荐使用注解

用注解进行事务控制(推荐)

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--
    开启注解扫描,扫描@Transactional
-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

在类上或者方法上加上@Transactional就能进行事务控制了

默认值为@Transactional(readOnly = false)

如果不想用XML进行配置,也可以用纯注解的方式

package com.chayedan.config;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import javax.xml.crypto.Data;

@Configuration
@ComponentScan("com.chayedan")
@PropertySource("classpath:db.properties")
//等同于 该配置<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
@EnableTransactionManagement
public class Config {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource getDataSource(){
        HikariDataSource hikariDataSource = new HikariDataSource();
        hikariDataSource.setDriverClassName(driver);
        hikariDataSource.setJdbcUrl(url);
        hikariDataSource.setUsername(username);
        hikariDataSource.setPassword(password);
        return hikariDataSource;
    }

    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

}