spring第三天

Spring03

回顾

IOC常用注解
	若使用注解,就需要在bean.xml中开启组件扫描
    	<context:component-scan base-package="com.itheima"/>
	作用在类上
    	@Component  将此类产生的对象交给spring容器管理
            @Controller
            @Service
            @Repository
   		@Scope("prototype|singleton")  //一般不用,使用的就是默认值singleton
	作用在方法上(了解)
		@PostConstruct
		@PreDestory
	作用在成员变量上(做注入),可以不提供set方法
		@Value
		@Autowired:
			先按照类型自动注入,只有一个此类对象的时候直接注入.
			若有多个,就会把变量名作为名字去容器中找,找到了直接注入,找不到报错;
			可以搭配@Qualifier("名字") 使用名字+类型完成注入   开发中一般不用@Qualifier
Spring新注解(理解或者了解)
    @Configuration:声明当前类是一个spring的配置类  == beans.xml
    @Bean:将非自定义对象交给IOC容器,作用在方法上,将方法的返回值(对象)交给容器管理
    @PropertySource:加载properties配置文件
    @ComponentScan:组件扫描
    @Import :导入其他注解类
整合junit:
	1.导入依赖(spring-test和junit)
	2.在测试类添加俩注解
		@ContextConfiguration() 指定配置文件或者配置类
		@RunWith() 不实用junit的测试类,改用SpringJunit4ClassRunner.class
	3.在需要测试的成员变量上使用@Autowired注入
转账案例:
	事务添加在service层.要想业务层和持久层处在同一个事务中,需要保证使用同一个connection连接对象?用ThreadLocal绑定conn对象
	在ConnectionManager中的两个方法
        从当前线程获取连接
        解绑当前线程且归还连接
    在TransactionManager中的四个方法
        开启事务
        提交事务
        回滚事务
        释放资源
注意:在dao中务必使用线程中绑定的连接来操作数据库.

内容介绍

aop:面向切面编程,使用动态代理技术实现代码和一些操作解耦合

  • xml方式
  • 注解方式

spring的dao层的解决方案:

  • JdbcTemplate:几乎和DBUtils一样

使用spring+springJDBCTemplate搭建转账环境(不考虑事务)

一 转账案例-解耦合

昨日案例存在的问题:

  1. 不但转账方法需要添加事务管理,其他的操作也需要添加事务.—代码重复
  2. 业务的代码和事务代码耦合在一起

解决方案:

  • 我们可以通过动态代理的方式,对service中的方法进行增强,目标就是:添加事务。这样就不会对业务层产生影响,解决了耦合性的问题和代码复用的问题

1 常用的动态代理技术

jdk动态代理(理解)

需求:在OrderService的save方法执行之前执行自己编写的类中打印时间的方法

public interface OrderService {
    void save();
    void findAll();
}
public class AopClass {
   public void printTime(){
       System.out.println("当前时间为:"+new Date());
   }
}
public class TestJdkProxy {
    @Test
    public void test0() {
        //1.创建目标对象
        OrderService orderService = new OrderServiceImpl();

        //2.使用动态代理创建代理对象,对save方法进行增强
        OrderService orderServiceProxy = (OrderService) Proxy.newProxyInstance(
                TestJdkProxy.class.getClassLoader(),//类加载器,使用任何一个自己编写的类获取即可
                orderService.getClass().getInterfaces(),//代理对象需要实现的接口,和目标对象实现的接口一样
                //增强的逻辑
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        //判断方法是否为save方法
                        if ("save".equals(method.getName())) {
                            //执行AopClass中的printTime方法
                            AopClass aopClass = new AopClass();
                            aopClass.printTime();
                        }

                        //方法执行原来的逻辑
                        Object result = method.invoke(orderService, args);

                        return result;
                    }
                }
        );


        orderServiceProxy.save();

        System.out.println("-------------");

        orderServiceProxy.findAll();
    }
}

CGLIB代理(了解)

使用的时候就需要导入cglib的jar包(spring内置了)

public class CategoryService {
    public void save(){
        System.out.println("save方法执行了");
    }

    public void findAll(){
        System.out.println("findAll方法执行了");
    }
}

导入spring-context就有cglib的包

package com.itheima.test;

import com.itheima.aop.AopClass;
import com.itheima.service.CategoryService;
import org.junit.Test;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class TestCGLIBProxy {
    @Test
    public void test0() {
        //1.创建目标对象
        CategoryService categoryService = new CategoryService();

        //2.创建代理对象
        CategoryService categoryServiceProxy = (CategoryService) Enhancer.create(CategoryService.class, new MethodInterceptor() {
            @Override
            /*
                method:当前执行的目标方法对象
                args:当前执行方法的参数列表
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //判断方法是否为save方法
                if ("save".equals(method.getName())) {
                    //执行AopClass中的printTime方法
                    AopClass aopClass = new AopClass();
                    aopClass.printTime();
                }

                //方法执行原来的逻辑
                Object result = method.invoke(categoryService, args);

                return result;
            }
        });


        categoryServiceProxy.save();
        System.out.println("------");
        categoryServiceProxy.findAll();
    }
}

2 使用动态代理优化代码

需求:

​ 使用动态代理技术,优化service层的代码,在service中所有业务方法执行之前开启事务,成功之后要提交事务,失败就要回滚事务,最终都要释放资源.

步骤分析:

  1. 复制我们昨天的有事务的模块,重命名为spring03_1_account_proxy
  2. 修改service中的代码,只剩下核心业务代码
  3. 编写一个类AccountServiceProxyFactory,在里面添加一个方法createProxy().
    • 在类上添加一个@Component注解,在方法上添加@Bean(name)注解
    • 注入TransactionManager对象,注入AccountService对象
    • 在方法中创建代理对象,添加事务代码
  4. 编写测试类
    • 从spring容器中获取service的代理对象

代码实现:

  • AccountService中删除事务逻辑代码
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    @Override
    public void transfer(String fromUser, String toUser, int money) throws Exception {

            //转出操作
            int i = accountDao.accountOut(fromUser, money);
            if(i != 1){
                throw new RuntimeException("转出失败");
            }

            //转入操作
            i = accountDao.accountIn(toUser,money);
            if(i != 1){
                throw new RuntimeException("转入失败");
            }
    }
}

  • 编写一个创建AccountService代理对象的工厂类
package com.itheima.tx;

import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.SQLException;

@Component //加入spring管理
public class AccountServiceProxyFactory {

    //目标对象
    @Autowired
    AccountService accountService;

    @Autowired
    TransactionManager transactionManager;

    //创建代理对象,加入spring容器
    @Bean("accountServiceProxy")
    public AccountService createProxy(){
        return (AccountService) Proxy.newProxyInstance(
                AccountServiceProxyFactory.class.getClassLoader(),
                accountService.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result = null;

                        try {
                            //开启事务
                            transactionManager.beginTransaction();

                            //目标方法执行原来的逻辑
                            result = method.invoke(accountService, args);

                            //执行之后,提交事务
                            transactionManager.commit();
                        } catch (Exception e) {
                            e.printStackTrace();
                            //若有异常,回滚事务
                            transactionManager.rollback();

                            //通知调用者
                            throw e;
                        } finally {
                            //无论如何,释放资源
                            transactionManager.releaseConn();
                        }
                        return result;
                    }
                }
        );
    }
}

  • 编写测试类,注入service的代理对象

二 SpringAOP简介

aop:面向切面编程,他不是一种技术而是一种思想,解决:在不破坏源代码的情况下,实现对业务方法的增强.可以减少重复代码,提高代码重用性,让我们开发者只关心核心业务逻辑的代码

常见的应用场景:

  • 日志
  • 测试代码性能
  • 事务控制

aop思想底层实现技术:JDK、CGLIB,

根据是否有接口选择使用其中一种技术.

相关术语

* target:目标对象
* proxy:代理对象
* joinPoint:连接点,目标对象的所有方法
* pointcut:切点,需要被增强的方法
* advice:通知 (增强的方法)
* aspect:切面, 切点+通知(声明对那些方法在什么时候执行那些操作)
* weaving:织入,动词,将通知织入到切点的过程

三 基于XML的AOP开发

1 快速入门

需求:在执行UserService中save方法之前,执行通知(增强)类中的beforeBeginTransaction方法

步骤分析:

  1. 创建模块,导入依赖:spring-context(已经包含了spring-aop),spring-test,junit,aspectjweaver(aspectj框架)
  2. 创建UserService及其实现类,添加save方法
    • 在spring配置文件中加入spring容器
  3. 创建TransactionManager(通知类),添加beforeBeginTransaction方法
    • 在spring配置文件中加入spring容器
  4. 在spring配置文件中配置aop
    • 配置切面(在切入点执行之前执行通知类中某个方法)
  5. 测试

代码实现

UserService

package com.itheima.service;

public interface UserService {
    void save();
    void findAll();
}

UserServiceImpl

package com.itheima.service.impl;

import com.itheima.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    public void save() {
        System.out.println("userService 中的save方法执行了");
    }

    public void findAll() {
        System.out.println("userService 中的findAll方法执行了");
    }
}

TransactionManager 通知类

package com.itheima.aop;

import org.springframework.stereotype.Component;

//通知(增强)类
@Component
public class TransactionManager {
    public void beforeBeginTransaction(){
        System.out.println("开启事务");
    }
}

beans.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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.itheima"/>

    <!--aop配置-->
    <aop:config>
        <!--
            配置切面:切入点+通知
            aspect:切面
                ref属性:指定增强(通知)类的对象
        -->
        <aop:aspect ref="transactionManager">
            <!--
                before:前置通知,在切入点执行之前
                    method:指定通知类中通知(增强方法)
                    pointcut:切入点
            -->
            <aop:before method="beforeBeginTransaction"  pointcut="execution(public void com.itheima.service.impl.UserServiceImpl.save())"/>
        </aop:aspect>
    </aop:config>
</beans>

测试类

@ContextConfiguration("classpath:beans.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestAOP {

    @Autowired
    UserService userService;

    @Test
    public void test0() {
        userService.save();

        System.out.println("----");

        userService.findAll();
    }

}


1 切入点(切点)表达式

execution([修饰符] 返回值 包名.类名.方法名(参数类型列表))
例:
execution(void com.itheima.service.impl.AccountServiceImpl.transfer(String,String,int))
提示: 表达式中可以使用 * 和 ..
	*	任意
	..  可以作用在包上和参数上
    	包上:当前包及其子包
    	参数上:参数任意

例如:

  • void com.itheima.service.impl.UserServiceImpl.save(User) :

  • * com.itheima.service.impl.UserServiceImpl.*() :

  • * com.itheima.service.impl.UserServiceImpl.*(…) :

  • * com.itheima.service.impl.*.*(…) :

  • * com.itheima.service…*.*(…) :

  • * com.itheima.service…*.find*(…) :

  • void com.itheima.service.impl.UserServiceImpl.save(User) :指定类中的指定方法,返回值为void,参数为User类型

  • * com.itheima.service.impl.UserServiceImpl.*() : 指定类中任意无参方法,返回值任意

  • * com.itheima.service.impl.UserServiceImpl.*(…) : 指定类中任意方法,返回值任意,参数任意

  • * com.itheima.service.impl.*.*(…) : 指定包下的任意类中的任意方法

  • * com.itheima.service…*.*(…) : 指定包及其子包下任意类中的任意方法

  • * com.itheima.service…*.find*(…) : 指定包及其子包下任意类中的以find开头的方法

2 通知类型

before:前置通知,在切入点执行之前

after-returning:后置通知,在切入点执行成功之后

after-throwing:异常通知,在切入点执行失败之后(发生异常)

after:最终通知,无论如何都要执行

around:环绕通知,以上通知的任意组合

//通知(增强)类
public class TransactionManager {
    public void beforeBeginTransaction(){
        System.out.println("开启事务");
    }

    public void afterReturningCommit(){
        System.out.println("提交事务");
    }

    public void afterThrowingRollback(){
        System.out.println("回滚事务");
    }

    public void afterRelease(){
        System.out.println("释放资源");
    }
}

<aop:aspect ref="transactionManager">
    <!--在切入点执行的什么时候 执行通知类中那个方法-->
    <!--前置通知-->
    <aop:before method="beforeBeginTransaction" pointcut="execution(public void com.itheima.service.impl.UserServiceImpl.save())"/>

    <!--后置通知-->
    <aop:after-returning method="afterReturningCommit" pointcut="execution(* com.itheima.service..*.save(..))"/>

    <!--异常通知-->
    <aop:after-throwing method="afterThrowingRollback" pointcut="execution(* com.itheima.service..*.save(..))"/>

    <!--最终通知-->
    <aop:after method="afterRelease" pointcut="execution(* com.itheima.service..*.save(..))"/>
</aop:aspect>

  1. 后置通知和异常通知不会同时出现
  2. 若一个方法执行的时候,需要加两种(含)之上的通知的话,建议大家使用环绕通知

3 环绕通知

在通知类中添加的方法

/*
            ProceedingJoinPoint:获取切入点(目标方法)
            注意:切入点执行时的返回值要返回回去
     */
public Object aroundTX(ProceedingJoinPoint pjp) throws Throwable {
    Object result = null;
    try {
        //开启事务
        beforeBeginTransaction();

        //切入点执行
        result = pjp.proceed();

        //提交事务
        afterReturningCommit();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
        //回滚事务
        afterThrowingRollback();

        //通知调用者
        throw throwable;
    } finally {
        //释放资源
        afterRelease();
    }

    return  result;
}

beans.xml

一个逻辑就使用一种通知即可

  • 若一种通知能解决逻辑的话就使用指定的通知即可
  • 若需要多种通知才能解决逻辑的话 就使用环绕通知,不要使用多种通知的组合了.

4 抽取切入点表达式

四 基于注解的AOP开发

1 快速入门(注解+XML)

需求:在执行UserService中save方法的时候,添加环绕通知

步骤分析:

  1. 复制刚才模块,重命名为spring03_3_aop_xml_anno
  2. 在通知类上添加一个注解 @Aspect:声明当前类是一个通知类
  3. 修改beans.xml
    • 开启组件扫描
    • 开启aop注解支持(自动代理)
  4. 在通知类中的方法上使用通知的注解方式声明.
  5. 测试

代码实现:

通知类的代码:

beans.xml

    <!--开启组件扫描-->
    <context:component-scan base-package="com.itheima"/>

    <!--开启aop注解支持(aop自动代理)-->
    <aop:aspectj-autoproxy/>

2 抽取切入点

3 纯注解

步骤分析

  1. 复制spring03_aop_xml_anno,重命名为spring03_aop_anno
  2. 提供一个spring的配置类(例如:SpringConfig类)
    • 开启组件扫描的注解
    • 开启aop的注解支持(自动代理)
@ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class TestAOPHello {
    @Autowired
    UserService userService;

    @Test
    public  void testHello(){
        userService.save();
        userService.findAll();
    }
}

五 使用AOP优化转账案例

使用xml+注解方式优化

步骤分析

  1. 复制spring03_1_account_proxy,重命名为:spring03_5_account_aop
  2. 添加依赖 aspectjweaver
  3. 删除AccountServiceProxyFactory类
  4. 把TransactionManager变成通知类
    • @Aspect
  5. 在通知类中编写一个方法:aroundTX,作为环绕通知
    • @Around(“execution(* com.itheima.service…*.*(…))”)
  6. 修改beans.xml
    • 添加开启组件扫描
    • 添加开启aop注解支持(自动代理)

代码实现

TransactionManage

//事务管理器
@Component
@Aspect //声明自己是一个通知类
public class TransactionManager {

    @Autowired
    private ConnectionManager connectionManager;

    @Around("execution(* com.itheima.service..*.*(..))")//环绕通知
    public Object aroundTX(ProceedingJoinPoint pjp) throws Throwable {
        Object result = null;
        try {
            beginTransaction();

            //执行原来的逻辑
            result = pjp.proceed();

            commit();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            rollback();

            //通知调用层
            throw  throwable;
        } finally {
            release();
        }

        return result;
    }

    //开启事务的方法
    public void beginTransaction() throws SQLException {
        //获取线程上的连接,开启事务
        connectionManager.getThreadConnection().setAutoCommit(false);
    }

    //提交事务的方法
    public void commit() throws SQLException {
        //获取线程上的连接,提交事务
        connectionManager.getThreadConnection().commit();
    }

    //回滚事务的方法
    public void rollback() {
        //获取线程上的连接,回滚事务
        try {
            connectionManager.getThreadConnection().rollback();
        } catch (SQLException e) {
        }
    }

    //释放资源的方法
    public void release() {
        //获取线程上的连接,重置事务状态
        try {
            connectionManager.getThreadConnection().setAutoCommit(true);
            connectionManager.release();
        } catch (SQLException e) {
        }
    }

}


beans.xml添加aop注解支持

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--加载properties-->
    <context:property-placeholder location="classpath:db.properties"/>

    <!--开启组件扫描-->
    <context:component-scan base-package="com.itheima"/>

    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置queryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>

    <!--开启aop注解支持:自动代理-->
    <aop:aspectj-autoproxy/>
</beans>

测试类

@ContextConfiguration("classpath:beans.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestService {

    @Autowired
    AccountService accountService;

    @Test
    public void testTransfer() throws Exception {
        accountService.transfer("tom","jackson",100);
    }
}

六 Spring的JdbcTemplate

1 JdbcTemplate概述

JdbcTemplate是Spring中的一款工作在Dao层的轻量级框架.

它的使用与DBUtils类似

核心对象

new JdbcTemplate(DataSource ds)

核心方法

方法名作用
int update(sql,Object … args)主要执行DML语句
T queryForObject(sql,Class resultType,Object … args)执行DQL语句,返回简单类型
T queryForObject(sql,RowMapper<>(resultType.class),Object … args)执行DQL语句,返回指定的对象
使用BeanPropertyRowMapper类映射
List<T> query(sql,RowMapper<>(resultType.class),Object … args)执行DQL语句,返回对象列表
int[] batchUpdate(sql,List<Object[]> args)批量执行DML语句

api路径:解压今日资料下的压缩包
快速入门-保存

向account添加一条记录

步骤分析:

  1. 新建模块,导入依赖(mysql驱动,druid,spring-context,spring-jdbc,spring-test和junit)
  2. 复制前天的JdbcUtils类和db.properties
  3. 创建DemoDao
    • 在类中提供save()方法
  4. 在save方法中
    • 创建一个JdbcTemplate对象(数据源)
    • 调用update方法
  5. 测试一下

pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.32</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.9</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>


2 Spring整合JdbcTemplate

步骤分析

  1. 创建AccountDao及其实现类 ,添加注解加入spring管理
  2. 编写save,findById,findAll,findTotalCount,batchInsert方法
  3. 编写beans.xml
    • 加载properties文件
    • 开启组件扫描
    • 配置数据源
    • 配置jdbcTemplate
  4. 测试

代码实现

pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.32</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.9</version>
    </dependency>
</dependencies>

beans.xml

<context:property-placeholder location="classpath:db.properties"/>
<context:component-scan base-package="com.itheima"/>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>
<!--配置jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <constructor-arg name="dataSource" ref="dataSource"/>
</bean>

AccoountDaoImpl

@Repository
public class AccountDaoImpl implements AccountDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public int save(Account account) {
        return jdbcTemplate.update("insert into account values(null,?,?)",account.getName(),account.getMoney());
    }

    @Override
    public Account findById(int id) {
        return jdbcTemplate.queryForObject("select * from account where id = ?",new BeanPropertyRowMapper<>(Account.class),id);
    }


    @Override
    public List<Account> findAll() {
        return jdbcTemplate.query("select * from account",new BeanPropertyRowMapper<>(Account.class));
    }

    @Override
    public int findTotalCount() {
        return jdbcTemplate.queryForObject("select count(1) from account",int.class);
    }

    @Override
    public int[] batchInsert(List<Object[]> list) {
        return jdbcTemplate.batchUpdate("insert into account values(null,?,?)",list);
    }
}


测试类

@ContextConfiguration("classpath:beans.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestAccountDao {

    @Autowired
    AccountDao accountDao;

    @Test
    public void testSave(){
        Account account = new Account();
        account.setName("肉丝儿");
        account.setMoney(60);

        accountDao.save(account);
    }

    @Test
    public void testFindById(){
        System.out.println(accountDao.findById(3));//使用queryForObject方法必须能找到唯一的结果,否则就会报错
    }

    @Test
    public void testFindAll(){
        List<Account> list = accountDao.findAll();
        if (list!=null) {
            for (Account account : list) {
                System.out.println(account);
            }
        }
    }

    @Test
    public void testFindTotal(){
        System.out.println(accountDao.findTotalCount());
    }

    @Test
    public void testBatchInsert(){
        List<Object[]> list = new ArrayList<>();
        list.add(new Object[]{"jerry",1000});
        list.add(new Object[]{"rose",1000});

        int[] arr = accountDao.batchInsert(list);
        System.out.println(Arrays.toString(arr));
    }
}

七 使用JdbcTemplate搭建转账环境

需求:使用JdbcTemplate来搭建,使用xml+注解配置的方式(不考虑事务)

步骤分析:

  1. 新建模块,导入依赖:(mysql驱动,druid,spring-context,spring-jdbc,spring-test和junit),下次上课的时候还需要导入aspectjweaver
  2. 复制db.properties
  3. 创建AccountDao及其实现类,添加注解@Repository
    • 注入JdbcTemplate
    • 编写两个方法 accountOut和accountIn
  4. 创建AccountService及其实现类,添加注解@Service
    • 注入AccountDao
    • 编写transfer方法
  5. 编写beans.xml
    • 加载properties文件
    • 开启组件扫描
    • 配置数据源
    • 配置jdbcTemplate
  6. 测试

代码实现:

AccountDaoImpl

@Repository
public class AccountDaoImpl implements AccountDao {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Override
    public int accountOut(String fromUser, int money) {
        return jdbcTemplate.update("update account set money = money - ? where name = ?",money,fromUser);
    }

    @Override
    public int accountIn(String toUser, int money) {
        return jdbcTemplate.update("update account set money = money + ? where name = ?",money,toUser);
    }
}

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    AccountDao accountDao;

    @Override
    public void transfer(String fromUser, String toUser, int money) {

        //转出操作
        int i = accountDao.accountOut(fromUser, money);
        if(i != 1){
            throw new RuntimeException("转出失败");
        }

        //转入操作
        i = accountDao.accountIn(toUser, money);
        if(i != 1){
            throw new RuntimeException("转入失败");
        }

    }
}

<?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">

    <context:property-placeholder location="classpath:db.properties"/>
    <context:component-scan base-package="com.itheima"/>
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" 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>
</beans>

@ContextConfiguration("classpath:beans.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestTransfer {

    @Autowired
    AccountService accountService;

    @Test
    public void testTransfer(){
        accountService.transfer("tom","jack",100);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值