spring(四)


一. Spring 中的 JdbcTemplate

1.1 JdbcTemplate 概述

  • 它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。spring 框架为我们提供了很多 的操作模板类。
  • 操作关系型数据的:JdbcTemplate,HibernateTemplate
  • 操作 nosql 数据库的:RedisTemplate
  • 操作消息队列的:JmsTemplate

JdbcTemplate在 spring-jdbc-5.0.2.RELEASE.jar 中,在导包的时候,除了要导入这个 jar 包 外,还需要导入一个 spring-tx-5.0.2.RELEASE.jar(它是和事务相关的)。

**作用:**用于和数据库交互,实现对表的CRUD操作

1.2 JdbcTemplate 对象的创建

可以参考它的源码,来查看:

public JdbcTemplate() {
    
}
public JdbcTemplate(DataSource dataSource) {
    setDataSource(dataSource);
    afterPropertiesSet();
}
public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
    setDataSource(dataSource);
    setLazyInit(lazyInit);
    afterPropertiesSet();
}

除了默认构造函数之外,其它两个都需要提供一个数据源。既然有set方法,依据之前的依赖注入,可以在配置文件中配置这些对象。

1.3 环境搭建

创建一个maven工程

pom.xml文件导入需要的依赖

    <packaging>jar</packaging>

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

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

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>

创建账户的实体类:

package com.xsh.domain;

import java.io.Serializable;

/**
 * 账户的实体类
 */
public class Account implements Serializable {

    private Integer id;
    private String name;
    private Float money;
	//此处已省略getter,setter,toString方法...
}

1.4 JdbcTemplate的最基本用法

此处使用spring的内置数据源DriverManagerDataSource,其它数据源还有C3P0, DBCP等

package com.xsh.jdbctemplate;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

/**
 * JdbcTemplate的最基本用法
 */
public class JdbcTemplateDemo1 {

    public static void main(String[] args) {
        //准备数据源:spring的内置数据源DriverManagerDataSource
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/test");
        ds.setUsername("root");
        ds.setPassword("123456");

        //1.创建JdbcTemplate对象
        JdbcTemplate jt = new JdbcTemplate();
        //2.给jt设置数据源
        jt.setDataSource(ds);
        //3.执行操作
        jt.execute("insert into account(name,money)values('ccc',1000)");
    }
}

1.5 可选择将数据库连接的信息配置到属性文件中

  • 定义属性文件

    在resources目录下新建jdbc.properties文件:

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///test
jdbc.username=root
jdbc.password=123456
  • 引入外部的属性文件

    方式一:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    	<property name="location" value="classpath:jdbc.properties"/>
    </bean>
    

    方式二:

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

二. JdbcTemplate 在dao中的使用

方法一:在 dao 中定义 JdbcTemplate

如果用注解配置,使用方法一:

IAccountDao:

package com.xsh.dao;

import com.xsh.domain.Account;

/**
 * 账户的持久层接口
 */
public interface IAccountDao {

    /**
     * 根据Id查询账户
     */
    Account findAccountById(Integer accountId);

    /**
     * 根据名称查询账户
     */
    Account findAccountByName(String accountName);

    /**
     * 更新账户
     */
    void updateAccount(Account account);
}

AccountDaoImpl:

package com.xsh.dao.impl;

import com.xsh.dao.IAccountDao;
import com.xsh.domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import java.util.List;

/**
 * 账户的持久层实现类
 */
public class AccountDaoImpl implements IAccountDao {

    private JdbcTemplate jdbcTemplate;
   
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
    
    @Override
    public Account findAccountById(Integer accountId) {
        List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
        return accounts.isEmpty()?null:accounts.get(0);
    }

    @Override
    public Account findAccountByName(String accountName) {
        List<Account> accounts =jdbcTemplate.query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
        if(accounts.isEmpty()){
            return null;
        }
        if(accounts.size()>1){
            throw new RuntimeException("结果集不唯一");
        }
        return accounts.get(0);
    }

    @Override
    public void updateAccount(Account account) {
        jdbcTemplate.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
    }
}

配置bean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://http://cdn.xiongsihao.com.springframework.org/schema/beans"
       xmlns:xsi="http://http://cdn.xiongsihao.com.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://http://cdn.xiongsihao.com.springframework.org/schema/beans
        http://http://cdn.xiongsihao.com.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 配置账户的持久层-->
    <bean id="accountDao" class="com.xsh.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

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

    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>
</beans>

测试查看结果:

package com.xsh.jdbctemplate;

import com.xsh.dao.IAccountDao;
import com.xsh.domain.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class JdbcTemplateDemo4 {

    public static void main(String[] args) {
        //1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取对象
        IAccountDao accountDao = ac.getBean("accountDao",IAccountDao.class);

        Account account = accountDao.findAccountById(1);
        System.out.println(account);

        account.setMoney(30000f);
        accountDao.updateAccount(account);
    }
}

方法二 : 让 dao 继承 JdbcDaoSupport(常用)

当使用xml配置,使用方法二,因为JdbcDaoSupport是jar包中的类,jar包中的JdbcTemplate无法使用@Autowired注解,因为jar包中的内容是只读的无法被修改:

因为在方法一中,当dao 有很多时,每个 dao 都有一些重复性的代码。下面就是重复代码:

private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
	this.jdbcTemplate = jdbcTemplate;
}

所以可以通过继承JdbcDaoSupport来去除注入setJdbcTemplate的重复代码:

修改bean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://http://cdn.xiongsihao.com.springframework.org/schema/beans"
       xmlns:xsi="http://http://cdn.xiongsihao.com.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://http://cdn.xiongsihao.com.springframework.org/schema/beans
        http://http://cdn.xiongsihao.com.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 配置账户的持久层-->
    <bean id="accountDao" class="com.xsh.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--去除注入JdbcTemplate,直接注入dataSource,因为JdbcDaoSupport已经帮我们实现了JdbcTemplate的创建-->
    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>
</beans>

AccountDaoImpl:继承JdbcDaoSupport, 使用super.getJdbcTemplate( )执行sql语句

package com.xsh.dao.impl;

import com.xsh.dao.IAccountDao;
import com.xsh.domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import java.util.List;

/**
 * 账户的持久层实现类
 */
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {

    @Override
    public Account findAccountById(Integer accountId) {
        List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
        return accounts.isEmpty()?null:accounts.get(0);
    }

    @Override
    public Account findAccountByName(String accountName) {
        List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
        if(accounts.isEmpty()){
            return null;
        }
        if(accounts.size()>1){
            throw new RuntimeException("结果集不唯一");
        }
        return accounts.get(0);
    }

    @Override
    public void updateAccount(Account account) {
        super.getJdbcTemplate().update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
    }
}

三. JdbcTemplate 的增删改查操作

package com.xsh.jdbctemplate;

import com.xsh.domain.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * JdbcTemplate的CRUD操作
 */
public class JdbcTemplateDemo3 {

    public static void main(String[] args) {
        //1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取对象
        JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
        //3.执行操作
        //保存
//        jt.update("insert into account(name,money)values(?,?)","eee",3333f);
        //更新
//        jt.update("update account set name=?,money=? where id=?","test",4567,7);
        //删除
//        jt.update("delete from account where id=?",8);
        //查询所有
//        List<Account> accounts = jt.query("select * from account where money > ?",new AccountRowMapper(),1000f);
//        List<Account> accounts = jt.query("select * from account where money > ?",new BeanPropertyRowMapper<Account>(Account.class),1000f);
//        for(Account account : accounts){
//            System.out.println(account);
//        }
        //查询一个
//        List<Account> accounts = jt.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),1);
//        System.out.println(accounts.isEmpty()?"没有内容":accounts.get(0));

        //查询返回一行一列(使用聚合函数,但不加group by子句)
        Long count = jt.queryForObject("select count(*) from account where money > ?",Long.class,1000f);
        System.out.println(count);


    }
}

/**
 * 自定义Account的封装策略,相当于spring提供的BeanPropertyRowMapper
 */
class AccountRowMapper implements RowMapper<Account>{
    /**
     * 把结果集中的数据封装到Account中,然后由spring把每个Account加到集合中
     * @param rs
     * @param rowNum
     * @return
     * @throws SQLException
     */
    @Override
    public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
        Account account = new Account();
        account.setId(rs.getInt("id"));
        account.setName(rs.getString("name"));
        account.setMoney(rs.getFloat("money"));
        return account;
    }
}

四. spring事物深入

  • JavaEE 体系进行分层开发,事务处理位于业务层,Spring 提供了分层设计 业务层的事务处理解决方 案。

  • spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我 们学习的重点是使用配置的方式实现。

  • spring 框架为我们提供了一组事务控制的接口。这组接口是在spring-tx-5.0.2.RELEASE.jar 中。

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

4.1 事物控制的APi

(1) PlatformTransactionManager

Spring所有事务代理类都是基于PlatformTransactionManager接口的实现。

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

//获得事务信息
TransactionStatus getTransaction(TransactionDefinition definition) 

//提交事务
void commit(TransactionStatus status) 
//回滚事务
void rollback(TransactionStatus status)

在实际开发中都是使用它的实现类,如下:

//用于Spring JDBC以及Mybatis框架的事务代理
DataSourceTransactionManager
//用于Hibernate框架事务代理
HibernateTransactionManager
//用于Jpa框架的事务代理
JpaTransactionManager
//用于JDO框架的事务代码
JdoTransactionManager
//用于Jta事务代理,一个事务跨多资源必须要使用
JtaTransactionManager

(2) TransactionDefinition

TransactionDefinition接口是用于定义一个事务,它定义了Spring事务管理的五大属性

源码,有以下方法:

public interface TransactionDefinition {
     int PROPAGATION_REQUIRED = 0;
     int PROPAGATION_SUPPORTS = 1;
     int PROPAGATION_MANDATORY = 2;
     int PROPAGATION_REQUIRES_NEW = 3;
     int PROPAGATION_NOT_SUPPORTED = 4;
     int PROPAGATION_NEVER = 5;
     int PROPAGATION_NESTED = 6;
     int ISOLATION_DEFAULT = -1;
     int ISOLATION_READ_UNCOMMITTED = 1;
     int ISOLATION_READ_COMMITTED = 2;
     int ISOLATION_REPEATABLE_READ = 4;
     int ISOLATION_SERIALIZABLE = 8;
     int TIMEOUT_DEFAULT = -1;
     int getPropagationBehavior();//事务的传播行为
     int getIsolationLevel();//事务的隔离级别
     int getTimeout();//事务超时时间
     boolean isReadOnly();//是否只读
     String getName();//获取事物对象名称
 }

事务的传播行为:

  • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选 择(默认值)
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
  • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
  • REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • NEVER:以非事务方式运行,如果当前存在事务,抛出异常
  • NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。

超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置。

是否是只读事务:建议查询时设置为只读。

(3) TransactionStatus

TransactionStatus接口代表了一个事务本身,提供了一个简单的控制事务执行和查询事务状态的方法。PlatformTransactionManager接口的getTransaction()方法会返回一个TransactionStatus对象,该对象可能代表一个新的或者一个已经存在的事务。

TransactionStatus接口源码如下:

public interface TransactionStatus extends SavepointManager, Flushable {
     boolean isNewTransaction();//是否一个新的事务
     boolean hasSavepoint();//
     void setRollbackOnly();//将事务设置为只能回滚,不允许提交
     boolean isRollbackOnly();//查询事务是否已有回滚标志
     void flush();//刷新事物
     boolean isCompleted();//查询事务是否结束
 }

4.2 基于 XML 的声明式事务控制(配置方式)

修改转账案例的bean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://http://cdn.xiongsihao.com.springframework.org/schema/beans"
       xmlns:xsi="http://http://cdn.xiongsihao.com.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://http://cdn.xiongsihao.com.springframework.org/schema/aop"
       xmlns:tx="http://http://cdn.xiongsihao.com.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://http://cdn.xiongsihao.com.springframework.org/schema/beans
        http://http://cdn.xiongsihao.com.springframework.org/schema/beans/spring-beans.xsd
        http://http://cdn.xiongsihao.com.springframework.org/schema/tx
        http://http://cdn.xiongsihao.com.springframework.org/schema/tx/spring-tx.xsd
        http://http://cdn.xiongsihao.com.springframework.org/schema/aop
        http://http://cdn.xiongsihao.com.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置业务层-->
    <bean id="accountService" class="com.xsh.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!-- 配置账户的持久层-->
    <bean id="accountDao" class="com.xsh.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

    <!-- spring中基于XML的声明式事务控制配置步骤
        1、配置事务管理器
        2、配置事务的通知
                此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
                使用tx:advice标签配置事务通知
                    属性:
                        id:给事务通知起一个唯一标识
                        transaction-manager:给事务通知提供一个事务管理器引用
        3、配置AOP中的通用切入点表达式
        4、建立事务通知和切入点表达式的对应关系
        5、配置事务的属性
               是在事务的通知tx:advice标签的内部

     -->
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置事务的通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 配置事务的属性
                isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
                propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
                read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
                timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
                rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
                no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
        -->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" read-only="false"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
        </tx:attributes>
    </tx:advice>

    <!-- 配置aop-->
    <aop:config>
        <!-- 配置切入点表达式-->
        <aop:pointcut id="pt1" expression="execution(* com.xsh.service.impl.*.*(..))"></aop:pointcut>
        <!--建立切入点表达式和事务通知的对应关系 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
    </aop:config>
    
</beans>

4.3 基于注解的声明式事务控制

AccountServiceImpl:

package com.xsh.service.impl;

import com.xsh.dao.IAccountDao;
import com.xsh.domain.Account;
import com.xsh.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 账户的业务层实现类
 *
 * 事务控制应该都是在业务层
 */
@Service("accountService")
@Transactional(propagation= Propagation.SUPPORTS,readOnly=true)//只读型事务的配置
public class AccountServiceImpl implements IAccountService{

    @Autowired
    private IAccountDao accountDao;


    @Override
    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);

    }


    //需要的是读写型事务配置
    @Transactional(propagation= Propagation.REQUIRED,readOnly=false)
    @Override
    public void transfer(String sourceName, String targetName, Float money) {
        System.out.println("transfer....");
            //2.1根据名称查询转出账户
            Account source = accountDao.findAccountByName(sourceName);
            //2.2根据名称查询转入账户
            Account target = accountDao.findAccountByName(targetName);
            //2.3转出账户减钱
            source.setMoney(source.getMoney()-money);
            //2.4转入账户加钱
            target.setMoney(target.getMoney()+money);
            //2.5更新转出账户
            accountDao.updateAccount(source);

            int i=1/0;

            //2.6更新转入账户
            accountDao.updateAccount(target);
    }
}

bean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://http://cdn.xiongsihao.com.springframework.org/schema/beans"
       xmlns:xsi="http://http://cdn.xiongsihao.com.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://http://cdn.xiongsihao.com.springframework.org/schema/aop"
       xmlns:tx="http://http://cdn.xiongsihao.com.springframework.org/schema/tx"
       xmlns:context="http://http://cdn.xiongsihao.com.springframework.org/schema/context"
       xsi:schemaLocation="
        http://http://cdn.xiongsihao.com.springframework.org/schema/beans
        http://http://cdn.xiongsihao.com.springframework.org/schema/beans/spring-beans.xsd
        http://http://cdn.xiongsihao.com.springframework.org/schema/tx
        http://http://cdn.xiongsihao.com.springframework.org/schema/tx/spring-tx.xsd
        http://http://cdn.xiongsihao.com.springframework.org/schema/aop
        http://http://cdn.xiongsihao.com.springframework.org/schema/aop/spring-aop.xsd
        http://http://cdn.xiongsihao.com.springframework.org/schema/context
        http://http://cdn.xiongsihao.com.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置spring创建容器时要扫描的包-->
    <context:component-scan base-package="com.xsh"></context:component-scan>

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

    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

    <!-- spring中基于注解 的声明式事务控制配置步骤
        1、配置事务管理器
        2、开启spring对注解事务的支持
        3、在需要事务支持的地方使用@Transactional注解
     -->
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 开启spring对注解事务的支持-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

</beans>

五. Spring5 的新特性

spring5.0 在 2017 年 9 月发布了它的 GA(通用)版本。该版本是基于 jdk8 编写的,所以 jdk8 以下版本 将无法使用。同时,可以兼容 jdk9 版本。

5.1 基于 JDK8 的反射增强

package com.xsh.test;

import java.lang.reflect.Method;

public class Test {
	
	//循环次数定义:10亿次
	private static final int loopCnt = 1000 * 1000 * 1000;

	public static void main(String[] args) throws Exception {
		//输出jdk的版本
		System.out.println("java.version=" + System.getProperty("java.version"));
		t1();
		t2();
		t3();
	}

	// 每次重新生成对象
	public static void t1() {
		long s = System.currentTimeMillis();
		for (int i = 0; i < loopCnt; i++) {
			Person p = new Person();
			p.setAge(31);
		}
		long e = System.currentTimeMillis();
		System.out.println("循环10亿次创建对象的时间:" + (e - s));
	}

	// 同一个对象
	public static void t2() {
		long s = System.currentTimeMillis();
		Person p = new Person();
		for (int i = 0; i < loopCnt; i++) {
			p.setAge(32);
		}
		long e = System.currentTimeMillis();
		System.out.println("循环10亿次给同一对象赋值的时间: " + (e - s));
	}
	
	//使用反射创建对象
	public static void t3() throws Exception {
		long s = System.currentTimeMillis();
		Class<Person> c = Person.class;
		Person p = c.newInstance();
		Method m = c.getMethod("setAge", Integer.class);
		for (int i = 0; i < loopCnt; i++) {
			m.invoke(p, 33);
		}
		long e = System.currentTimeMillis();
		System.out.println("循环10亿次反射创建对象的时间:" + (e - s));
	}

	static class Person {
		private int age = 20;

		public int getAge() {
			return age;
		}

		public void setAge(Integer age) {
			this.age = age;
		}
	}
}

运行结果:

java.version=1.7.0_72 循环10亿次创建对象的时间:6212 循环10亿次给同一对象赋值的时间: 3025 循环10亿次反射创建对象的时间:290400

java.version=1.8.0_101 循环10亿次创建对象的时间:20 循环10亿次给同一对象赋值的时间: 150 循环10亿次反射创建对象的时间:3759

可以对比发现,对于jdk1.8,反射创建对象时间大大缩减

5.2 @NonNull 和@Nullable

用 @Nullable 和 @NotNull 注解来显示表明可为空的参数和以及返回值。这样就够在编译的时候处 理空值而不是在运行时抛出 NullPointerExceptions。

5.3 日志记录方面

Spring Framework 5.0 带来了 Commons Logging 桥接模块的封装, 它被叫做 spring-jcl 而 不是标准的 Commons Logging。当然,无需任何额外的桥接,新版本也会对 Log4j 2.x, SLF4J, JUL ( java.util.logging) 进行自动检测。

spring
  • 作者:管理员(联系作者)
  • 发表时间:2019-11-29 07:07
  • 版权声明:自由转载-非商用-非衍生-保持署名(null)
  • undefined
  • 评论