Spring_four

Day-four

1、Spring JdbcTemlate基本使用

①导入spring-jdbc和spring-tx 【前者封装着Jdbc的模板对象,后者是事务控制的对象】
②创建数据库和实体类
③创建JdbcTemlate对象
④执行数据操作

导入spring-jdbc和spring-tx
<!--c3p0数据库驱动包-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        
<!--MySQL驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        
<!--spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.4.RELEASE</version>
        </dependency>
        
        <!--spring-tx-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        
<!--Junit基本包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

测试类
//测试JdbcTemplate开发步骤
public class JdbcTemplateTest {
    @Test
    public void test01() throws Exception {
        //1、创建数据源对象
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        //2、设置数据库信息
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        //3、创建JDBC模板对象:JdbcTemplate
        JdbcTemplate template = new JdbcTemplate();
        //4、设置数据源对象,告诉数据库在哪(内部会获取数据库连接对象)
        template.setDataSource(dataSource);
        //5、执行SQL
        int i = template.update("insert into account values(?,?)","张三",5000);
        System.out.println(i);//影响行数:1
    }
}

1.4 Spirng产生JdbcTemplate对象

上述使用JdbcTemlate是比较原始的。
分析发现:
创建JdbcTemplate对象依赖于DataSource对象,而DataSource对象依赖数据库信息,也就是说,我们需要创建2个对象,还要给数据库连接对象设置依赖的属性。
再分析发现:
它们所依赖的,都可以使用setXXX方法来设置属性,所以我们可以把这2个对象创建的控制权交给Spring,在设置Bean的时候,分别使用set方式来进行依赖注入。

下面我们来看看具体怎么实现:

applicationContext.xml
        <!--c3p0数据源对象-->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
            <property name="user" value="root"/>
            <property name="password" value="root"/>
        </bean>
        <!--jdbc模板对象-->
        <bean id="jdbcTemlate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
测试类
    @Test
    //测试Spring产生jdbcTemplate对象
    public void test02() throws Exception {
        //1、加载配置文件,创建Spring容器对象
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、获取JdbcTemplate对象
        JdbcTemplate template = app.getBean(JdbcTemplate.class);
        //3、执行SQL
        int row = template.update("insert into account value (?,?)", "刘德华", 9000);
        //4、打印影响行数
        System.out.println(row);

    }

1.5 Spirng产生JdbcTemplate对象之抽取数据

我们之前也有学过,为了程序代码更加解耦,我们可以把需要设置数据库信息抽取到1个配置文件中,到时候再动态读取。
下面就简单展示一下代码:
(跟上一步的代码一模一样,就多了个jdbc.properties)

jdbc.properties

在resource文件下。

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.user=root
jdbc.password=root
applicationContext.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: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/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--引入jdbc.properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
        <!--c3p0数据源对象-->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driver}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="user" value="${jdbc.user}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
        <!--jdbc模板对象-->
        <bean id="jdbcTemlate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
</beans>

【记得:】到时候这个applicationContext.xml都是这样一套配置JDBC的。

1.5 Spirng产生JdbcTemplate对象之更新和修改SQL

其实,步骤跟上边一样的。只是这里使用Spring集成Junit测试,记得配置pom.xml导包(Spring集成Junit包)
Spring集成Junit测试类:

@RunWith(SpringJUnit4ClassRunner.class) //叫Spring内核帮我运行
@ContextConfiguration("classpath:applicationContext.xml")//告诉Spring测试哪个配置文件的Bean(从此获取对象)
public class JdbcTemplateCRUDTest {
    //需要什么对象就注入什么对象(容器有的对象)
    @Autowired
    private JdbcTemplate template;
    @Test
    public void testUpdate(){
        int row = template.update("update account set money = ? where name = ?",100000,"刘德华");
        System.out.println(row);//打印影响行数
    }
}

1.5 Spirng产生JdbcTemplate对象之查询SQL

这里的步骤跟上边一样,只是演示一下使用Spring如何使用JdbcTemplate的CRUD。其实跟以前学得差不多。
这里着重介绍以下几点:

  • BeanPropertyRowMapper《T》(T.class)

他是MapBean Property Row Mappe 翻译中文就是:“Bean属性与行的映射”,它是RowMapper(行映射)的实现类。

  • Bean属性=实体类的setxxx方法中的xxx;
  • 行=查询数据库得到的行数(查询结果集)。
  • 映射:是指,我们查询数据库结果会1行1行地显示,每一行的列名都会去寻找JavaBean的属性进行映射,映射成功就进行数据封装,而至少要有1个列名和1个Bean属性产生映射并封装数据到Bean,如果1个都没有就会报异常。

这个“T”代表什么?
”T“代表你想要封装的对象。

  • queryForObejct

query是查询的意思。
如果只是使用简单的select就返回1个对象,无论能查出几行。
如果是查询聚合函数,那么返回你想要封装的包装类

  • query

query是查询的意思。
如果查询出1行,就返回1个Bean对象
如果查询出多行,就返回Bean对象的List集合
Account实体类:


/**
 * 实体类:
 *      用于封装数据库数据
 */
public class Account {
    private String name;
    private double monet;
    //get/set方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMonet() {
        return monet;
    }

    public void setMonet(double monet) {
        this.monet = monet;
    }
    //toString方法

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                ", monet=" + monet +
                '}';
    }
}

Spring集成Junit测试类

@RunWith(SpringJUnit4ClassRunner.class) //叫Spring内核帮我运行
@ContextConfiguration("classpath:applicationContext.xml")//告诉Spring测试哪个配置文件的Bean(从此获取对象)
public class JdbcTemplateCRUDTest {
    //需要什么对象就注入什么对象(容器有的对象)
    @Autowired
    private JdbcTemplate template;
    //总记录数
    @Test
    public void testQueryCount() {
        String sql ="select count(*) from account";
        Long sum = template.queryForObject(sql, Long.class);
        System.out.println(sum);
    }
    //查询1个对象
    @Test
    public void testQueryForObject() {
        String sql = "select * from account where name =?";
        template.queryForObject(sql,new BeanPropertyRowMapper<Account>(Account.class),"刘德华");
    }
    //查询多个对象
    @Test
    public void testQueryAll() {
        String sql = "select * from account";
        List<Account> list = template.query(sql, new BeanPropertyRowMapper<Account>(Account.class));
    }

小总结

在这里插入图片描述

2、事务控制

文章转载

a、编程式事务控制

在这里插入图片描述

1.1 PlatformTransactionManage:事务管理器

在这里插入图片描述

  • PlatformTransactionManager(事务管理器):它只是Spring提供管理事务的操作方法的接口。对于不同dao层技术,就有不同的实现类。
  • 事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数是 TransactionDefinition类 ,这个类就定义了一些基本的事务属性。
1.2 TransactractionDefinition:事务定义对象

在这里插入图片描述
getxxx方法,xxx是该类的属性,这个属性在该类定义成)常量。(funal+成员变量
什么是事务的基本属性?

  • 事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。
    事务属性包含了5个方面:
    1、隔离级别
    2、传播行为
    3、是否超时
    4、是否只读
    5、回滚规则
  • 这些属性描述了这个事务具体是什么样的:它是什么隔离级别啊?具有什么传播行为呢?进行事务的操作的有效时间是多少?这个事务是否为只读(只查询)?

TransactractionDefinition:事务定义对象

定义了5个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等的常量。

1.2.1 事务传播行为:
在这里插入图片描述
业务场景:
A调用B,B根据A有没有事务来做出行为。

使用这个业务场景解释一下某个事务传播行为的定义:
required:A调用B,B看A有没有设置事务管理,如果没有,B就创建新的事务管理,如果有就一起使用这个事务。

1.3 TransactionStatus:描述事务运动状态对象

在这里插入图片描述
事务管理器 + 事务定义 = 运动状态

这个运动状态不是我们主动去设置的,它是我们执行事务管理的被动提示。
所以,我们在设置Spring配置时,设置【事务管理器 + 事务定义】就好了。

b、XML声明式事务控制

2.1 什么是声明式事务控制

就是在XML配置文件声明事务管理,让Spirng帮我们去进行事务管理,不需要自己动手写代码。这样子就将事务管理和逻辑代码2个部分进行了分开。
Spring声明式事务控制底层就是AOP:切点就是某个方法,通知就是事务管理

2.2 环境搭建【转账案例】
①创建数据库

在这里插入图片描述

②pom.xml导入基本包
<dependencies>

        <!--Spring基本包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>

        <!--Mysql驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>

        <!--c3p0驱动包-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <!--Spring'S jdbc 包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        
        <!--Spring集成单元测试-->
        <dependency>
            <groupId></groupId>
            <artifactId></artifactId>
        </dependency>
    </dependencies>
③appliztionContext.xml配置Bean
<?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: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/context http://www.springframework.org/schema/context/spring-context.xsd">
    
<!--引入jdbc.properties文件-->
    <Context:property-placeholder location="classpath:jdbc.properties"/>
    
    <!--c3p0数据源Bean-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!--JdbcTemlate:Spring's JDBC模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--AccountDaoImpl-->
    <bean id="accountDao" class="com.itheima.dao.Ipml.AccountDaoIpml">
        <property name="template" ref="jdbcTemplate"/>
    </bean>
    
    <!--AccountServiceImpl:目标对象-->
    <bean id="accountService" class="com.itheima.service.Ipml.AccountServiceIpml">
        <property name="accountDao" ref="accountDao"/>
    </bean>
</beans>
④创建dao层、service层、controller层

AccountDaoIpml:

public class AccountDaoIpml implements AccountDao {

    private JdbcTemplate template; //定义依赖为成员变量

    public void setTemplate(JdbcTemplate template) { //set方法注入依赖对象
        this.template = template;
    }
    //转账方法
    public void out(String outMan, double money) {//谁转账,转多少
        String sql = "update account set money=money-? where name=?";
        template.update(sql, money, outMan);
    }
    //收账方法
    public void in(String inMan, double money) {//谁转账,转多少
        String sql = "update account set money=money-? where name=?";
        template.update(sql, money, inMan);
    }
}

AccountServiceIpml:

public class AccountServiceIpml implements AccountService {

    private AccountDao dao;//讲依赖对象作为成员变量

    public void setAccountDao(AccountDao dao) {//set方法注入依赖
        this.dao = dao;
    }
    //转账操作
    public void transfer(String outMan, String inMan, double money) {//谁转账,谁收账,交易多少钱
        dao.out(outMan,money);
        int i = 1/0; //手动发生异常
        dao.in(inMan,money);
    }
}

⑤controller层测试

AccountController:

public class AccountController {
    public static void main(String[] args) {
        //1、加载配置文件,创建Spring容器
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、获取对象
        AccountService service = (AccountService) app.getBean("accountService");
        //3、执行方法
        service.transfer("吴彦祖","陈冠希",1000);
    }
}

MySQL中每一条SQL都是一个事务,当多个独立的事务同时操作一批数据,如果没有被事务管理着就可能会出现一些问题。
为了解决这些问题我们以前是这样手动地添加的:
在这里插入图片描述
但是,这只是对于1个方法的设置,如果我们需要设置很多方法呢?而且以后设置了还得修改,是不是这样很麻烦?
所以,我们得利用AOP思想,将事务管理当成增强并且抽取出来,被管理的方法作为切点,在XML配置文件中再将其结合(织入)

不是很重要的提示:

  • Spring已经帮我们封装好了事务管理的代码,我们只要给对于的方法配置好就行了。
  • 一般增强的方法都是在业务逻辑层,而此案列中业务逻辑层转出和转入钱的方法就要被管理事务。也就是说,【目标对象】就是业务逻辑层Service
2.3 Spring事务控制-基于xml(代码结合2.2)

在这里插入图片描述

①pom.xml导包
        <!--AOP框架:aspectj的织入 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.4</version>
        </dependency>
        
        <!---事务管理的包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
    </dependencies>
②配置ApplicationContext.xml

记得导命名空间:context(引入)、aop(aop织入)、tx(事务)

<?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:Context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"

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

       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.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">

<!--引入jdbc.properties文件-->
    <Context:property-placeholder location="classpath:jdbc.properties"/>

    <!--c3p0数据源Bean-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>	//set注入依赖
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--JdbcTemlate:Spring's JDBC模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>	//set注入依赖
    </bean>

    <!--AccountDaoImpl-->
    <bean id="accountDao" class="com.itheima.dao.Ipml.AccountDaoIpml">
        <property name="template" ref="jdbcTemplate"/>	//set注入依赖
    </bean>

    <!--AccountServiceImpl:目标对象(内部的方法就是切点)-->
    <bean id="accountService" class="com.itheima.service.Ipml.AccountServiceIpml">
        <property name="accountDao" ref="accountDao"/>	//set注入依赖
    </bean>

    <!--配置事务管理器对象:指定使用哪一种事务管理技术-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>	//set注入依赖:name=属性名
    </bean>

    <!--配置通知:事务的增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">//transaction-manager:给通知指定使用哪一种的事务管理技术
    	<tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    
    <!--配置织入:告诉Spring哪些方法需要增强-->
    <aop:config>
        <!--抽取切点-->
        <aop:pointcut id="txPointcut" expression="execution(* com.itheima.service.Ipml.*(..))"/>
        <!--声明切面:告诉Spring哪个是切面类-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>

advisor也是切面的意思,只是advisor是特定声明事务的,而aspect是用来声明普通类的切面的。【要区分2者配置的结构】

  • 为什么要设置【配置事务管理器对象】?

实现事务管理的实现类是后很多种的,我们要指定一种

  • 为什么配置事务管理器对象时要注入数据源?

首先,这个事务管理器对象是封装了我们操作事务的方法,而操作事务的方法本质上是通过连接对象调用的,而连接对象是通过数据源对象获取的。

③测试运行
④结果

如果转账中途报错,回滚事务;如果没出现异常,交易成功。

详解XML

在这里插入图片描述

知识要点

在这里插入图片描述
这3步基本是写死的了。

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

此处在XML的代码中进行修改。
在这里插入图片描述
我们一般开发的原则是,自己编写的类使用注解,第三方的类使用XML配置。

下面展示代码:

1、applicationContext.xml

这里我们移除了dao和service,增加了事务注解驱动和注解组件扫描。

<!--引入jdbc.properties文件-->
    <Context:property-placeholder location="classpath:jdbc.properties"/>

    <!--c3p0数据源Bean-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--JdbcTemlate:Spring's JDBC模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配置事务管理器对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/><!--注入依赖-->
    </bean>
    
    <!--注解组件扫描-->
    <Context:component-scan base-package="com.itheima"/>    

    <!--事务注解驱动:没加就没有事务增强功能-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
2、AccountDaoIpml
@Repository("accountDao")//告诉Spring帮我实例化Bean
public class AccountDaoIpml implements AccountDao {

    @Autowired  //自动注入依赖
    private JdbcTemplate template; //定义依赖为成员变量

    //转账方法
    public void out(String outMan, double money) {//谁转账,转多少
        String sql = "update account set money=money-? where name=?";
        template.update(sql, money, outMan);
    }
    //收账方法
    public void in(String inMan, double money) {//谁转账,转多少
        String sql = "update account set money=money-? where name=?";
        template.update(sql, money, inMan);
    }
}

3、AccountServiceIpml
@Service("accountService")  //告诉Spring帮我实例化Bean

//@Transactional    代表配置此类所有的方法设置为事务通知(参数随便)

public class AccountServiceIpml implements AccountService {
    @Autowired  //自动注入对象
    private AccountDao dao;//讲依赖对象作为成员变量
  
    }
//    @Transactional  //配置事务通知。(参数为定义的事务基本属性)
//    @Transactional(isolation = Isolation.READ_COMMITTED)
    @Transactional  //代表每个方法都有独立的事务管理
    public void xxx(){

    }


	 //转账操作                  ↓(配置通知的基本属性:可以有参数、无参)
    @Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.MANDATORY)
    public void transfer(String outMan, String inMan, double money) {//谁转账,谁收账,交易多少钱
        dao.out(outMan,money);
        dao.in(inMan,money);
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值