Spring简介与入门04

第1章    Spring中的JdbcTemplate

1.1        JdbcTemplate概述

它是spring框架中提供的一个对象,是对原始Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类,入下图所示:


我们今天的主角在spring-jdbc-4.24.RELEASE.jar中,我们在导包的时候,除了要导入这个jar包外,还需要导入一个spring-tx-4.2.4.RELEASE.jar(它是和事务相关的)。

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        spring中配置数据源

1.3.1      环境搭建

1.3.2      编写spring的配置文件

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

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans.xsd">   

</beans>

1.3.3      配置数据源

我们之前已经接触过了两个数据源,一个是C3P0,一个是DBCP。要想使用这两数据源都需要导入对应的jar包。

1.3.3.1    配置C3P0数据源

导入c3p0-0.9.2.1.jar到工程的lib目录。在spring的配置文件中配置:

<bean id="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"></property>

    <property name="jdbcUrl" value="jdbc:mysql:///spring_day04"></property>

    <property name="user" value="root"></property>

    <property name="password" value="1234"></property>

</bean>

1.3.3.2    配置DBCP数据源

导入commons-dbcp.jar和commons-pool.jar到工程的lib目录。在spring的配置文件中配置:

<!-- 配置数据源 -->

<bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource">

    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>

    <property name="url" value="jdbc:mysql:///spring_day04"></property>

    <property name="username" value="root"></property>

    <property name="password" value="1234"></property>

</bean>

1.3.3.3    配置spring内置数据源

spring框架也提供了一个内置数据源,我们也可以使用spring的内置数据源,它就在spring-jdbc-4.2.4.REEASE.jar包中:

<bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>

    <property name="url" value="jdbc:mysql:///spring_day04"></property>

    <property name="username" value="root"></property>

    <property name="password" value="1234"></property>

</bean>

1.3.4     将数据库连接的信息配置到属性文件中:

【定义属性文件】

jdbc.driverClass=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql:///spring_day02

jdbc.username=root

jdbc.password=123

【引入外部的属性文件】

一种方式:

    <!-- 引入外部属性文件: -->

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

    <property name="location" value="classpath:jdbc.properties"/>

    </bean>

二种方式:

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

 

1.4        JdbcTemplate的增删改查操作

1.4.1      前期准备

创建数据库:

create database spring_day04;

use spring_day04;

创建表:

createtable account(

    id intprimarykey auto_increment,

    name varchar(40),

    money float

)characterset utf8 collateutf8_general_ci;

1.4.2      在spring配置文件中配置JdbcTemplate

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

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 配置一个数据库的操作模板: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:///spring_day04"></property>

    <property name="username"value="root"></property>

    <property name="password"value="1234"></property>

</bean>

</beans>

1.4.3      最基本使用

public classJdbcTemplateDemo2 {

    publicstatic voidmain(String[] args) {

        //1.获取Spring容器

        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

        //2.根据id获取bean对象

        JdbcTemplate jt = (JdbcTemplate)ac.getBean("jdbcTemplate");

        //3.执行操作

        jt.execute("insertinto account(name,money)values('eee',500)");

    }

}

1.4.4      保存操作

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.执行操作

        //保存

        jt.update("insertinto account(name,money)values(?,?)","fff",5000);

    }

}

1.4.5      更新操作

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.执行操作

        //修改

        jt.update("updateaccount set money = money-? where id = ?",300,6);

    }

}

1.4.6      删除操作

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.执行操作

        //删除

        jt.update("deletefrom account where id = ?",6);

    }

}

1.4.7      查询所有操作

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 AccountRowMapper(), 500);

        for(Accounto : accounts){

            System.out.println(o);

        }

    }

}

public class AccountRowMapper implements RowMapper<Account>{

    @Override

    public Account mapRow(ResultSet rs, introwNum) throws SQLException {

        Account account = new Account();

        account.setId(rs.getInt("id"));

        account.setName(rs.getString("name"));

        account.setMoney(rs.getFloat("money"));

        returnaccount;

    }   

}

1.4.8      查询一个操作

使用RowMapper的方式:常用的方式

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> as = jt.query("select * from account where id = ? ",

                                        new AccountRowMapper(), 55);

        System.out.println(as.isEmpty()?"没有结果":as.get(0));

    }

}

使用ResultSetExtractor的方式:不常用的方式

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.执行操作

        //查询一个

        Account account = jt.query("select * from account where id = ?",

                                    new AccountResultSetExtractor(),3);

        System.out.println(account);

    }

}

1.4.9      查询返回一行一列操作

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.执行操作

        //查询返回一行一列:使用聚合函数,在不使用group by字句时,都是返回一行一列。最长用的就是分页中获取总记录条数

        Integer total = jt.queryForObject("select count(*) from account where money > ?",Integer.class,500);

        System.out.println(total);

    }

}

1.5        在dao中使用JdbcTemplate

1.5.1      准备实体类

/**

 * 账户的实体

 * @authorzhy

 */

public class Account implements Serializable {

    private Integer id;

    private String name;

    private Float money;

    public Integer getId() {

        returnid;

    }

    publicvoid setId(Integer id) {

        this.id = id;

    }

    public String getName() {

        returnname;

    }

    publicvoid setName(String name) {

        this.name = name;

    }

    public Float getMoney() {

        returnmoney;

    }

    publicvoid setMoney(Float money) {

        this.money = money;

    }

    @Override

    public String toString() {

        return"Account [id=" + id + ", name=" + name + ", money=" + money + "]";

    }

}

1.5.2      第一种方式:在dao中定义JdbcTemplate

/**

 *账户的接口

 * @authorzhy

 */

public interface IAccountDao {   

    /**

     * 根据id查询账户信息

     * @param id

     * @return

     */

    Account findAccountById(Integer id);

    /**

     * 根据名称查询账户信息

     * @return

     */

    Account findAccountByName(String name);

    /**

     * 更新账户信息

     * @param account

     */

    void updateAccount(Account account);

}

/**

 * 账户的持久层实现类

 * @authorzhy

 * 此版本的dao,需要给dao注入JdbcTemplate

 */

public class AccountDaoImpl implements IAccountDao {

    private JdbcTemplate jdbcTemplate;  

    public void setJdbcTemplate(JdbcTemplatejdbcTemplate) {

        this.jdbcTemplate = jdbcTemplate;

    }

    @Override

    public Account findAccountById(Integer id) {

        List<Account> list =  jdbcTemplate.query("select * from account where id = ? ",new AccountRowMapper(),id);

        return list.isEmpty()?null:list.get(0);

    }

    @Override

    public Account findAccountByName(Stringname) {

        List<Account> list =  jdbcTemplate.query("select * from account where name = ? ",new AccountRowMapper(),name);

        if(list.isEmpty()){

            returnnull;

        }

        if(list.size()>1){

            thrownew RuntimeException("结果集不唯一,不是只有一个账户对象");

        }

        return list.get(0);

    }

    @Override

    public void updateAccount(Account account) {

        jdbcTemplate.update("update account setmoney = ? where id = ? ",account.getMoney(),account.getId());

    }

}

配置文件

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

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans.xsd">   

    <!-- 配置一个dao -->

    <bean id="accountDao"class="com.itheima.dao.impl.AccountDaoImpl">

        <!-- 注入jdbcTemplate -->

        <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:///spring_day04"></property>

        <property name="username" value="root"></property>

        <property name="password" value="1234"></property>

    </bean>

</beans>

思考:

    此种方式有什么问题吗?

答案:

    有个小问题。就是我们的dao有很多时,每个dao都有一些重复性的代码。下面就是重复代码:

    private JdbcTemplate jdbcTemplate;   

    publicvoid setJdbcTemplate(JdbcTemplatejdbcTemplate) {

        this.jdbcTemplate = jdbcTemplate;

    }

    能不能把它抽取出来呢?

    请看下一小节。

1.5.3      第二种方式:让dao继承JdbcDaoSupport

JdbcDaoSupport是spring框架为我们提供的一个类,该类中定义了一个JdbcTemplate对象,我们可以直接获取使用,但是要想创建该对象,需要为其提供一个数据源:具体源码如下:

public abstract class JdbcDaoSupport extends DaoSupport {

    //定义对象

    private JdbcTemplate jdbcTemplate;

    //set方法注入数据源,判断是否注入了,注入了就创建JdbcTemplate

    public final void setDataSource(DataSource dataSource) {

    if(this.jdbcTemplate== null || dataSource != this.jdbcTemplate.getDataSource()){               //如果提供了数据源就创建JdbcTemplate

            this.jdbcTemplate = createJdbcTemplate(dataSource);

            initTemplateConfig();

        }

    }

    //使用数据源创建JdcbTemplate

    protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {

        return new JdbcTemplate(dataSource);

    }   

    //当然,我们也可以通过注入JdbcTemplate对象

    public final void setJdbcTemplate(JdbcTemplate jdbcTemplate) {

        this.jdbcTemplate = jdbcTemplate;

        initTemplateConfig();

    }

    //使用getJdbcTmeplate方法获取操作模板对象

    public final JdbcTemplate getJdbcTemplate(){

      return this.jdbcTemplate;

    }

/**

 * 账户的接口

 * @authorzhy

 */

public interface IAccountDao {   

    /**

     * 根据id查询账户信息

     * @param id

     * @return

     */

    Account findAccountById(Integer id);

    /**

     * 根据名称查询账户信息

     * @return

     */

    Account findAccountByName(String name);   

    /**

     * 更新账户信息

     * @param account

     */

    void updateAccount(Account account);

}

/**

 * 账户的持久层实现类

 * @authorzhy

 * 此版本dao,只需要给它的父类注入一个数据源

 */

public class AccountDaoImpl2 extends JdbcDaoSupport implements IAccountDao {

    @Override

    public Account findAccountById(Integer id) {

        //getJdbcTemplate()方法是从父类上继承下来的。

        List<Account> list =getJdbcTemplate().query("select * from account where id = ? ",new AccountRowMapper(),id);

        return list.isEmpty()?null:list.get(0);

    }

    @Override

    public Account findAccountByName(Stringname) {

        //getJdbcTemplate()方法是从父类上继承下来的。

        List<Account> list =  getJdbcTemplate().query("select * fromaccount where name = ? ",new AccountRowMapper(),name);

        if(list.isEmpty()){

            returnnull;

        }

        if(list.size()>1){

            thrownew RuntimeException("结果集不唯一,不是只有一个账户对象");

        }

        return list.get(0);

    }

    @Override

    public void updateAccount(Account account) {

        //getJdbcTemplate()方法是从父类上继承下来的。

        getJdbcTemplate().update("update account setmoney = ? where id = ? ",account.getMoney(),account.getId());

    }

}

配置文件:

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

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans.xsd">   

<!--配置dao2 -->

<bean id="accountDao2"class="com.itheima.dao.impl.AccountDaoImpl2">

    <!-- 注入dataSource -->

    <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:///spring_day04"></property>

        <property name="username" value="root"></property>

        <property name="password" value="1234"></property>

    </bean>

</beans>

思考:

    两版Dao有什么区别呢?

答案:

    第一种在Dao类中定义JdbcTemplate的方式,适用于所有配置方式(xml和注解都可以)。

    第二种让Dao继承JdbcDaoSupport的方式,只能用于基于XML的方式,注解用不了。

第2章  Spring中的事务控制

2.1        Spring事务控制我们要明确的

第一:

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

第二:

         spring框架为我们提供了一组事务控制的接口。具体在后面的第二小节介绍。这组接口是在spring-tx-4.2.4.RELEASE.jar中。

第三:

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

2.2        Spring中事务控制的API介绍

2.2.1         PlatformTransactionManager

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

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

真正管理事务的对象

org.springframework.jdbc.datasource.DataSourceTransactionManager   使用Spring JDBCiBatis 进行持久化数据时使用

org.springframework.orm.hibernate3.HibernateTransactionManager     使用Hibernate版本进行持久化数据时使用

2.2.2         TransactionDefinition

它是事务的定义信息对象,里面有如下方法:

2.2.2.1    事务的隔离级别

2.2.2.2   事务的传播行为

REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)

SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)

MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常

REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。

NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起

NEVER:以非事务方式运行,如果当前存在事务,抛出异常

NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类似的操作。

2.2.2.3    超时时间

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

2.2.2.4    是否是只读事务

建议查询时设置为只读。

2.2.3         TransactionStatus

此接口提供的是事务具体的运行状态,方法介绍如下图:

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

2.3.1      环境搭建

2.3.1.1    第一步:拷贝必要的jar包到工程的lib目录

2.3.1.2    第二步:创建spring的配置文件并导入约束

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

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

     xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

             http://www.springframework.org/schema/beans/spring-beans.xsd

             http://www.springframework.org/schema/tx

             http://www.springframework.org/schema/tx/spring-tx.xsd

             http://www.springframework.org/schema/aop

             http://www.springframework.org/schema/aop/spring-aop.xsd">

</beans>

2.3.1.3    第三步:准备数据库表和实体类

创建数据库:

create database spring_day04;

use spring_day04;

创建表:

createtable account(

    id intprimarykey auto_increment,

    name varchar(40),

    money float

)characterset utf8 collateutf8_general_ci;

/**

 * 账户的实体

 * @authorzhy

 */

public class Account implements Serializable {

    private Integer id;

    private String name;

    private Float money;

    public Integer getId() {

        returnid;

    }

    public void setId(Integer id) {

        this.id = id;

    }

    public String getName() {

        returnname;

    }

    public void setName(String name) {

        this.name = name;

    }

    public Float getMoney() {

        returnmoney;

    }

    public void setMoney(Float money) {

        this.money = money;

    }

    @Override

    public String toString() {

        return"Account [id=" + id + ", name=" + name + ", money=" + money + "]";

    }

}

2.3.1.4    第四步:编写业务层接口和实现类

/**

 * 账户的业务层接口

 * @authorzhy

 */

public interface IAccountService {   

    /**

     * 根据id查询账户信息

     * @param id

     * @return

     */

    Account findAccountById(Integer id);//查   

    /**

     * 转账

     * @param sourceName    转出账户名称

     * @param targeName     转入账户名称

     * @param money         转账金额

     */

    void transfer(String sourceName,StringtargeName,Float money);//增删改

}

/**

 * 账户的业务层实现类

 * @authorzhy

 */

public class AccountServiceImpl implements IAccountService {   

    private IAccountDao accountDao;  

    public void setAccountDao(IAccountDao accountDao){

        this.accountDao = accountDao;

    }

    @Override

    public Account findAccountById(Integer id) {

        return accountDao.findAccountById(id);

    }

    @Override

    public void transfer(String sourceName, StringtargeName, Float money) {

        //1.根据名称查询两个账户

        Account source = accountDao.findAccountByName(sourceName);

        Account target = accountDao.findAccountByName(targeName);

        //2.修改两个账户的金额

        source.setMoney(source.getMoney()-money);//转出账户减钱

        target.setMoney(target.getMoney()+money);//转入账户加钱

        //3.更新两个账户

        accountDao.updateAccount(source);

        int i=1/0;

        accountDao.updateAccount(target);

    }

}

2.3.1.5    第五步:编写Dao接口和实现类

/**

 *账户的持久层接口

 * @authorzhy

 */

public interface IAccountDao {   

    /**

     * 根据id查询账户信息

     * @param id

     * @return

     */

    Account findAccountById(Integer id);

    /**

     * 根据名称查询账户信息

     * @return

     */

    Account findAccountByName(String name);   

    /**

     * 更新账户信息

     * @param account

     */

    void updateAccount(Account account);

}

/**

 * 账户的持久层实现类

 * @authorzhy

 * 此版本dao,只需要给它的父类注入一个数据源

 */

public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {

    @Override

    public Account findAccountById(Integer id) {

        List<Account> list =getJdbcTemplate().query("select * from account where id = ? ",new AccountRowMapper(),id);

        return list.isEmpty()?null:list.get(0);

    }

    @Override

    public Account findAccountByName(Stringname) {

        List<Account> list =  getJdbcTemplate().query("select * fromaccount where name = ? ",new AccountRowMapper(),name);

        if(list.isEmpty()){

            returnnull;

        }

        if(list.size()>1){

            thrownew RuntimeException("结果集不唯一,不是只有一个账户对象");

        }

        return list.get(0);

    }

    @Override

    public void updateAccount(Account account) {

        getJdbcTemplate().update("update account setmoney = ? where id = ? ",account.getMoney(),account.getId());

    }

}

/**

 * 账户的封装类RowMapper的实现类

 * @authorzhy

 */

public class AccountRowMapper implements RowMapper<Account>{

    @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;

    }

}

2.3.1.6    第六步:在配置文件中配置业务层和持久层对

<!-- 配置service -->

<bean id="accountService"class="com.itheima.service.impl.AccountServiceImpl">

    <property name="accountDao" ref="accountDao"></property>

</bean>   

<!-- 配置dao -->

<bean id="accountDao"class="com.itheima.dao.impl.AccountDaoImpl">

    <!-- 注入dataSource -->

    <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:///spring_day04"></property>

    <property name="username" value="root"></property>

    <property name="password" value="1234"></property>

</bean>

2.3.2     配置步骤

2.3.2.1    第一步:配置事务管理器

<!-- 配置一个事务管理器 -->

<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <!-- 注入DataSource -->

    <property name="dataSource" ref="dataSource"></property>

</bean>

2.3.2.2    第二步:配置事务的通知引用事务管理器

<!-- 事务的配置 -->

<tx:advice id="txAdvice"transaction-manager="transactionManager">   

</tx:advice>

2.3.2.3    第三步:配置事务的属性

<!--tx:advice标签内部配置事务的属性 -->

<tx:attributes>

<!-- 指定方法名称:是业务核心方法

    read-only:是否是只读事务。默认false,不只读。

    isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。

    propagation:指定事务的传播行为。

    timeout:指定超时时间。默认值为:-1。永不超时。

    rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。没有默认值,任何异常都回滚。

    no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,任何异常都回滚。

    -->

    <tx:method name="*" read-only="false"propagation="REQUIRED"/>

    <tx:method name="find*" read-only="true"propagation="SUPPORTS"/>

</tx:attributes>

2.3.2.4    第四步:配置AOP-切入点表达式

<!-- 配置aop -->

<aop:config>

    <!-- 配置切入点表达式 -->

    <aop:pointcut expression="execution(*com.itheima.service.impl.*.*(..))" id="pt1"/>

</aop:config>

2.3.2.5    第五步:配置切入点表达式和事务通知的对应关系

<!-- aop:config标签内部:建立事务的通知和切入点表达式的关系 -->

<aop:advisor advice-ref="txAdvice"pointcut-ref="pt1"/>

2.4        基于注解的声明式事务控制(配置方式)重点

2.4.1      环境搭建

2.4.1.1    第一步:拷贝必备的jar包到工程的lib目录

2.4.1.2    第二步:创建一个类用于加载spring的配置

/**

 * 用于初始化spring容器的配置类

 * @authorzhy

 */

@Configuration

@ComponentScan(basePackages="com.itheima")

public class SpringConfiguration {

}

2.4.1.3    第三步:创建数据库表和实体类

和基于xml的配置相同。略

2.4.1.4    第四步:创建业务层接口和实现类

业务层接口和基于xml配置的时候相同。略

/**

 * 账户的业务层实现类

 * @authorzhy

 */

@Service("accountService")

public class AccountServiceImpl implements IAccountService {

    @Autowired

    private IAccountDao accountDao;

    @Override

    public Account findAccountById(Integer id) {

        returnaccountDao.findAccountById(id);

    }

    @Override

    public void transfer(String sourceName, StringtargeName, Float money) {

        //1.根据名称查询两个账户

        Account source = accountDao.findAccountByName(sourceName);

        Account target = accountDao.findAccountByName(targeName);

        //2.修改两个账户的金额

        source.setMoney(source.getMoney()-money);//转出账户减钱

        target.setMoney(target.getMoney()+money);//转入账户加钱

        //3.更新两个账户

        accountDao.updateAccount(source);

        int i=1/0;

        accountDao.updateAccount(target);

    }

}

2.4.1.5    第五步:创建Dao接口和实现类

Dao层接口和AccountRowMapper与基于xml配置的时候相同。略

@Repository("accountDao")

public class AccountDaoImpl implements IAccountDao {

    @Autowired

    private JdbcTemplate jdbcTemplate;   

    @Override

    public Account findAccountById(Integer id) {

        List<Account> list = jdbcTemplate.query("select * fromaccount where id = ? ",new AccountRowMapper(),id);

        return list.isEmpty()?null:list.get(0);

    }

    @Override

    public Account findAccountByName(Stringname) {

        List<Account> list =  jdbcTemplate.query("select * from account where name = ? ",new AccountRowMapper(),name);

        if(list.isEmpty()){

            returnnull;

        }

        if(list.size()>1){

            thrownew RuntimeException("结果集不唯一,不是只有一个账户对象");

        }

        return list.get(0);

    }

    @Override

    publicvoid updateAccount(Account account) {

        jdbcTemplate.update("update account setmoney = ? where id = ? ",account.getMoney(),account.getId());

    }

}

2.4.2      配置步骤

2.4.2.1    第一步:使用@Bean注解配置数据源

@Bean(name = "dataSource")

    publicDataSource createDS() throwsException {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setUsername("root");

        dataSource.setPassword("123");

        dataSource.setDriverClassName("com.mysql.jdbc.Driver");

        dataSource.setUrl("jdbc:mysql:///spring3_day04");

        returndataSource;

    }

2.4.2.2    第二步:使用@Bean注解配置配置事务管理器

@Bean

publicPlatformTransactionManager

        createTransactionManager(@Qualifier("dataSource")DataSource dataSource) {

    returnnewDataSourceTransactionManager(dataSource);

}

2.4.2.3    第三步:使用@Bean注解配置JdbcTemplate

@Bean

public JdbcTemplatecreateTemplate(@Qualifier("dataSource") DataSource dataSource)

{

    returnnew JdbcTemplate(dataSource);

}

2.4.2.4    第四步:在需要控制事务的业务层实现类上使用@Transactional注解

@Service("accountService")

@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)

public class AccountServiceImpl implements IAccountService {  

    @Autowired

    private IAccountDao accountDao;

    @Override

    public Account findAccountById(Integer id) {

        returnaccountDao.findAccountById(id);

    }

    @Override

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)

    publicvoid transfer(String sourceName, StringtargeName, Float money) {

        //1.根据名称查询两个账户

        Account source = accountDao.findAccountByName(sourceName);

        Account target = accountDao.findAccountByName(targeName);

        //2.修改两个账户的金额

        source.setMoney(source.getMoney()-money);//转出账户减钱

        target.setMoney(target.getMoney()+money);//转入账户加钱

        //3.更新两个账户

        accountDao.updateAccount(source);

        //int i=1/0;

        accountDao.updateAccount(target);

    }

}

该注解的属性和xml中的属性含义一致。该注解可以出现在接口上,类上和方法上。

出现接口上,表示该接口的所有实现类都有事务支持。

出现在类上,表示类中所有方法有事务支持

出现在方法上,表示方法有事务支持。

以上三个位置的优先级:方法>类>接口。

2.4.2.5    第五步:使用@EnableTransactionManagement开启spring对注解事务的的支持

@Configuration

@EnableTransactionManagement

publicclass SpringTxConfiguration {

    //里面配置数据源,配置JdbcTemplate,配置事务管理器。在之前的步骤已经写过了。

}

2.4.3      特殊说明

我们在2.4章节中介绍的是纯注解的方式,没有spring的xml配置文件。spring框架也支持使用注解+xml混合配置文件的方式。

我们只需要把事务管理器,JdbcTemplate和数据源配置到xml中,并且在xml中开启事务的支持就行了,具体配置如下:

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

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

     xmlns:tx="http://www.springframework.org/schema/tx"

     xmlns:context="http://www.springframework.org/schema/context"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

             http://www.springframework.org/schema/beans/spring-beans.xsd

             http://www.springframework.org/schema/tx

            http://www.springframework.org/schema/tx/spring-tx.xsd

             http://www.springframework.org/schema/aop

             http://www.springframework.org/schema/aop/spring-aop.xsd

             http://www.springframework.org/schema/context

             http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置spring要扫描的包 -->

    <context:component-scan base-package="com.itheima"></context:component-scan>    

    <!-- 开启spring对注解事务的支持 -->

    <tx:annotation-driven transaction-manager="transactionManager"/>                      

    <!-- 配置JdbcTemplate -->

    <bean id="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate">

        <property name="dataSource" ref="dataSource"></property>

    </bean>

    <!-- 配置事务管理器 -->

<bean id="transactionManager"

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <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:///spring_day04"></property>

        <property name="username" value="root"></property>

        <property name="password" value="1234"></property>

    </bean>

</beans>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值