第四十八天:Spring04 Spring整合事务及Spring模板模式

1. 事务相关概念回顾

1.1 相关概念回顾

概念:一组对数据库的操作,要么同时成功,要么同时失败。

作用:保证一组对数据库的操作是一个原子操作,同时保证多个同时对数据库的操作尽量不受影响。

四大特性:ACID;原子性、移植性,隔离性,持久性。

事务并发访问的问题及隔离级别

  • 脏读 。解决方案,隔离级别调整为Read Committed(表级读锁)
  • 不可重复读。提高隔离级别到 RepeatableRead (行级写锁)
  • 幻读。提高隔离毕节到Serializable(表级写锁)

1.2 事务控制位置

  • 事务控制在业务层(service层)

2. Spring事务管理的核心对象(了解)

学顶层,用底层。

学习Spring事务管理的核心高层接口。

  • PlatformTransactionManager

    平台事务管理器,作用进行事务管理。

    有但不仅限于以下实现类

    • DataSourceTransactionManager 适用于SpringJDBC或MyBatis
    • HibernateTransactionManager 适用于Hibernate3.0及以上版本
    • JpaTransactionManager 适用于JPA
    • JdoTransactionManager 适用于JDO
    • JtaTransactionManager 适用于JTA

    此接口定义了事务的基本操作

    获取事务:TransactionStatus getTransaction(TransactionDefinition definition)

    提交事务:void commit(TransactionStatus status)

    回滚事务:void rollback(TransactionStatus status)

事务对业务层代码的一种增强,在事务方面的增强,其中获取事务(前置增强)、提交事务(后置增强)、回滚事务(异常增强)就是某个具体的增强,PlatformTransactionManager就是一个通知类/切面类。

  • TransactionDefinition

    封装定义事务参数的值(参数:隔离级别、是否只读、超时时间、传播行为)

    获取事务定义名称:String getName()

    获取事务的读写属性:boolean isReadOnly()

    获取事务隔离级别:int getIsolationLevel()

    获取事务超时时间:int getTimeout()

    获取事务传播行为特征:int getPropagationBehavior()

    Spring采用int类型枚举的方式表示不同的参数及其值

    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1
    int ISOLATION_READ_COMMITTED = 2
    int ISOLATION_REPEATABLE_READ = 4
    int ISOLATION_SERIALIZABLE = 8
    
  • TransactionStatus

    封装定义事务在某个时刻的状态信息(是否已经开启、是否已经提交、是否已经回滚)

    获取事务是否处于新开启事务状态:boolean isNewTransaction()

    获取事务是否处于已完成状态:boolean isCompleted()

    获取事务是否处于回滚状态:boolean isRollbackOnly()

    刷新事务状态:void flush()

    获取事务是否具有回滚存储点:boolean hasSavepoint()

    设置事务处于回滚状态:void setRollbackOnly()

  • 三者之间的关系(理解)

    平台事务管理器是Spring进行事务控制的核心对象,要根据事务属性定义器为当前事务设置好的参数来进行事务管理;事务在不同的时刻,其事务状态不一样,这个状态封装在TransactionStatus中,其中状态也可以做为影响事务管理的条件。

4. 案例环境

4.1 业务逻辑

银行转账业务

4.2 技术选型

基于Spring+Mybatis

4.3 相关配置和代码

  • 业务层接口提供转账操作

    /**
    * 转账操作
    * @param outName 出账用户名
    * @param inName 入账用户名
    * @param money 转账金额
    */
    public void transfer(String outName,String inName,Double money);
    
  • 业务层实现提供转账操作

    public void transfer(String outName,String inName,Double money){
        accountDao.inMoney(outName,money);
        accountDao.outMoney(inName,money);
    }
    
  • 数据层提供对应的入账与出账操作

    <update id="inMoney">
    update account set money = money + #{money} where name = #{name}
    </update>
    <update id="outMoney">
    update account set money = money - #{money} where name = #{name}
    </update>
    
    void inMoney(String name, double money);
    void outMoney(String name, double money);
    

编程式事务:通过编码的方式来控制事务

声明式事务

  • 基于xml配置的事务

  • 基于xml+注解的配置事务()

  • 基于注解配置的事务

5. 编程式事务(理解)

5.0 Spring控制事务的方式

  • 编程式事务:通过编码的方式来控制事务

  • 声明式事务:配置实现事务管理

    • xml方式的声明式事务

    • 注解+XML方式的声明式事务(最终选用)

    • 全注解方式的声明式事务

5.1 基本的编程式事务

修改业务层转账代码(核心业务代码),系统辅助功能代码入侵了核心业务代码

public void transfer(String outName,String inName,Double money){
    //创建事务管理器
    DataSourceTransactionManager dstm = new DataSourceTransactionManager();
    //为事务管理器设置与数据层相同的数据源
    dstm.setDataSource(dataSource);
    //创建事务定义对象
    TransactionDefinition td = new DefaultTransactionDefinition();
    //创建事务状态对象,用于控制事务执行
    TransactionStatus ts = dstm.getTransaction(td);
    
    
    
    accountDao.inMoney(outName,money);
    // int i = 1/0; //模拟业务层事务过程中出现错误
    accountDao.outMoney(inName,money);
    
    
 
    //提交事务
    dstm.commit(ts);
}

注意:业务层要注入与dao层相同的dataSource对象(底层原理:保证使用的是同一个连接对象)

5.2 使用AOP改造编程式事务

实现了,系统辅助功能代码 和 核心业务代码 解耦

业务层核心转账代码

public void transfer(String outName, String inName, Double money) {
    accountDao.inMoney(outName,money);
    int i = 1/0;
    accountDao.outMoney(inName,money);
}

切面类中事务增强代码

public class TxAdvice {

    // 保证使用的是同一个DataSource,所以要在切面类中注入dataSource(dao层同一个对象)
    private DataSource dataSource;
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Object transactionManager(ProceedingJoinPoint pjp) throws Throwable {
        //开启事务
        PlatformTransactionManager ptm = new DataSourceTransactionManager(dataSource);
        //事务定义
        TransactionDefinition td = new DefaultTransactionDefinition();
        //事务状态
        TransactionStatus ts = ptm.getTransaction(td);

        Object ret = pjp.proceed(pjp.getArgs());

        //提交事务
        ptm.commit(ts);
        return ret;
    }
}

配置织入关系

<bean id="txAdvice" class="com.company.aop.TxAdvice">
    <property name="dataSource" ref="dataSource"/>
</bean>

<aop:config>
    <aop:pointcut id="pt" expression="execution(* *..transfer(..))"/>
    <aop:aspect ref="txAdvice">
        <aop:around method="transactionManager" pointcut-ref="pt"/>
    </aop:aspect>
</aop:config>

6. 声明式事务

声明式事务:以配置的方式管理事务

配置方式有两种:xml注解

6.1 XML(理解)

6.1.1 入门范例,beans.xml
<!--装配平台事务管理器对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--
    配置事务的切面类,不需要我们自己编写这个类了
    定义事务管理的通知类,需要指定一个平台事务管理器对象
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <!--定义哪些业务方法会被事务控制,以及使用什么样的参数进行控制-->
    <tx:attributes>
        <!-- tx:method必须写,否则任何一个业务方法都不会被事务控制
 			name 要被事务控制的业务方法的名字 
			read-only等其他属性,配置当前这个方法的事务的属性:是否只读、超时时间……
		-->
        <tx:method name="transfer" read-only="false" />
    </tx:attributes>
</tx:advice>



<!-- 配置织入关系 -->
<aop:config>
    <!-- 切面 = 切点 + 通知 -->
    <aop:pointcut id="pt" expression="execution(* com.company.service..*ServiceImpl.*(..))"/>
    <!--
        aop:advisor 和 aop:aspect 功能一样,都是用于配置切面的信息
        前者是Spring专门为事务管理添加的一个新标签
     -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>

6.1.2 tx:attributes&tx:method

Spring事务控制是方法级别的,也就是可以为每个方法配置不同的事务管理属性。

tx:attributes对不同的方法进行事务控制、事务控制参数配置的父标签

tx:method配置哪些方法被事务控制、以及使用什么样的参数进行控制

<tx:advice id="txAdvice" transaction-manager="txManager">
    <!--
        Spring进行事务控制的级别:
            方法级别
     -->

    <!--定义哪些业务方法会被事务控制,以及使用什么样的参数进行控制-->
    <!-- 对不同的方法进行事务控制、事务控制参数配置的父标签 -->
    <tx:attributes>
        <!-- 配置哪些方法被事务控制、以及使用什么样的参数进行控制
            name属性用于指定哪些方法会被控制
            read-only="false"   只读/读写事务,默认是读写事务
            isolation="DEFAULT"  默认数据库的隔离级别
            timeout="-1"         默认不会超时
            propagation=""       传播行为
            rollback-for=""      配置异常类型名,抛出指定异常后必须回滚
            no-rollback-for=""   配置异常类型名,抛出指定异常后不回滚
         -->
        <tx:method name="transfer"/>
    </tx:attributes>
</tx:advice>

6.1.3 切点表达式和tx:methodname值关系

aop:config中切点表达式和 tx:advice中 tx:method是否重复,不重复的话,作用分别是什么?

前者仅仅明确了哪些方法会被事务控制,但是没有事务控制是具体细节 — 相当于海选

后者指定被拦截成功的所有方法中,每个方法的事务到底是什么属性参数进行控制 — 按照特质进行培养包装宣传

6.1.4 工作中用法
<tx:advice transaction-manager="transactionManager" id="txAdvice">
    <tx:attributes>
        <!-- 
			工作中如何配置
            匹配原则:从上往下挨个匹配,只有匹配成功
         -->
        <tx:method name="find*" read-only="true" timeout="10"/>
        <!-- log代表的是系统辅助功能,不应该影响核心业务的运行 -->
        <tx:method name="*log" propagation="REQUIRES_NEW"/>
        <!-- 其他所有方法都走默认的事务管理 -->
        <tx:method name="*" read-only="false"/>
    </tx:attributes>
</tx:advice>
/*
成对出现
组件扫描 :<context:component-scan>|@ComponentScan 和 @Component;
aop自动代理:<aop:aspectj-autoproxy> | @EnableAspectjAutoProxy 和 @Aspect

事务管理:<tx:annotation-driven/> | @EnableTransactionManagement 和 @Transactional
*/

6.2 注解

6.2.1 注解 + XML配置

一个注解 + 一个标签

Spring配置文件beans.xml开启注解驱动

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

在要被事务控制的接口或者接口方法上添加@Transactional注解

@Transactional
public interface AccountService {}

通过注解的属性,调整事务的参数(工作中用法)

@Transactional  //保证当前类中所有的方法都被事务控制
public interface AccountService {
    
    @Transactional(readOnly= true,timeout=10) // 为当前方法的事务添加个性需求
    List<Account> findAll();
    
}

该注解添加在接口上还是实现类上,取决于你的需求:

  1. 如果加载接口上,该接口的所有实现类都会被事务控制
  2. 如果加载某个具体的实现类上,事务只会在当前类有效

注意:

  1. 配置注解驱动的时候,注意选择tx的命名空间(url后缀为tx的,否则会报错)
  2. 当类(接口)上、方法上都有事务注解并且参数不一致的时候,按照就近原则,以最近的为准
  3. 成对出现:tx:annotation-driven@Transactional
6.2.1 全注解

Spring配置类SpringConfig.java开启注解驱动,并通过@Bean注入平台事务管理器

@ComponentScan("com.company")
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement
public class SpringConfig(){
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;

    @Bean("dataSource")
    public DataSource getDataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }

    @Bean
    public PlatformTransactionManager transactionManager(@Autowired DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }

在要被事务控制的接口或者接口方法上添加@Transactional注解

@Transactional
public interface AccountService {}

通过注解的属性,调整事务的参数(工作中用法)

@Transactional  //保证当前类中所有的方法都被事务控制
public interface AccountService {
    
    @Transactional(readOnly= true,timeout=10) // 为当前方法的事务添加个性需求
    List<Account> findAll();
    
}

注意事项

  1. 成对出现:@EnableTransactionManagement@Transactional

7. 传播行为

7.1 概念

传播行为研究的是:业务层A方法调用其他方法B(C、D……)时,A、B(C、D……)这些方法执行期间如何控制事务的问题:被调用方法B如果看待处理调用方法A事务的问题。

结婚的时候彩礼类比说明

事务 – 彩礼房车

方法的调用者A – 男方 - 事务管理员

被调用的方法B – 女方 – 事务协调员

7.2 分类

总共七种

1603877022989

7.3 工作中用法

REQUIRED 这个是默认值

REQUIRES_NEW 应用场景,eg:取钱时候,打印小票方法可以配置该传播行为。

8. Spring模板

高频常用的代码封装成模板,通过AOP的方式,使用的时候直接在模板上填充个性数据即可。

8.1 Spring中常见的模板

  • TransactionTemplate
  • JdbcTemplate
  • RedisTemplate
  • RabbitTemplate
  • JmsTemplate
  • HibernateTemplate
  • RestTemplate

8.2 JDBCTemplate(了解)

  • 导入依赖坐标

    <!-- Spring-jdbc 内含JDBCTemplate --> 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    
    
    <!-- MySQL数据库驱动 --> 
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!-- Spring-context --> 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    
    <!-- 数据源 --> 
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.16</version>
    </dependency>
    <!-- Junit单元测试 --> 
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!-- Spring整合Junit --> 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    
    
  • JDBCTemplate注入进Spring容器

    public class JDBCConfig {
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String userName;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean("dataSource")
        public DataSource getDataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(userName);
            ds.setPassword(password);
            return ds;
        }
    
        //注册JdbcTemplate模块对象bean
        @Bean("jdbcTemplate")
        public JdbcTemplate getJdbcTemplate(@Autowired DataSource dataSource){
            return new JdbcTemplate(dataSource);
        }
    
        @Bean("jdbcTemplate2")
        public NamedParameterJdbcTemplate getJdbcTemplate2(@Autowired DataSource dataSource){
            return new NamedParameterJdbcTemplate(dataSource);
        }
    }
    
  • Dao层接口:AccountDao.java

    package com.company.dao;
    
    public interface AccountDao {
        void save(Account account);
        void delete(Integer id);
        void update(Account account);
        String findNameById(Integer id);
        Account findById(Integer id);
        List<Account> findAll();
        List<Account> findAll(int pageNum,int preNum);
        Long getCount();
    }
    
    
  • Dao层接口实现类:AccountDaoImpl.java

    package com.company.dao.impl;
    
    //dao注册为bean
    @Repository("accountDao")
    public class AccountDaoImpl implements AccountDao {
    
        //注入模板对象
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        public void save(Account account) {
            String sql = "insert into account(name,money)values(?,?)";
            jdbcTemplate.update(sql,account.getName(),account.getMoney());
        }
    
        public void delete(Integer id) {
            String sql = "delete from account where id = ?";
            jdbcTemplate.update(sql,id);
        }
    
        public void update(Account account) {
            String sql = "update account set name = ? , money = ? where id = ?";
            jdbcTemplate.update(sql, account.getName(),account.getMoney(),account.getId());
        }
    
        public String findNameById(Integer id) {
            String sql = "select name from account where id = ? ";
            //单字段查询可以使用专用的查询方法,必须制定查询出的数据类型,例如name为String类型
            return jdbcTemplate.queryForObject(sql,String.class,id );
        }
    
        public Account findById(Integer id) {
            String sql = "select * from account where id = ? ";
            //支持自定义行映射解析器
            RowMapper<Account> rm = new RowMapper<Account>() {
                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.getDouble("money"));
                    return account;
                }
            };
            return jdbcTemplate.queryForObject(sql,rm,id);
        }
    
        public List<Account> findAll() {
            String sql = "select * from account";
            //使用spring自带的行映射解析器,要求必须是标准封装
            return jdbcTemplate.query(sql,new BeanPropertyRowMapper<Account>(Account.class));
        }
    
        public List<Account> findAll(int pageNum, int preNum) {
            String sql = "select * from account limit ?,?";
            //分页数据通过查询参数赋值
            return jdbcTemplate.query(sql,new BeanPropertyRowMapper<Account>(Account.class),(pageNum-1)*preNum,preNum);
        }
    
        public Long getCount() {
            String sql = "select count(id) from account ";
            //单字段查询可以使用专用的查询方法,必须制定查询出的数据类型,例如数据总量为Long类型
            return jdbcTemplate.queryForObject(sql,Long.class);
        }
    }
    
    
  • Dao层接口实现类:AccountDaoImpl.java(使用具名参数传值)

    package com.company.dao.impl;
    
    
    //dao注册为bean
    @Repository
    //@Primary
    public class AccountDaoImpl2 implements AccountDao {
    
        //注入模板对象
        @Autowired
        private NamedParameterJdbcTemplate jdbcTemplate;
    
        public void save(Account account) {
            String sql = "insert into account(name,money)values(:name,:money)";
            Map pm = new HashMap();
            pm.put("name",account.getName());
            pm.put("money",account.getMoney());
            jdbcTemplate.update(sql,pm);
        }
    
        public void delete(Integer id)  { return null; }
        public void update(Account account)  { return null; }
        public String findNameById(Integer id)  { return null; }
        public Account findById(Integer id)  { return null; }
        public List<Account> findAll()  { return null; }
        public List<Account> findAll(int pageNum, int preNum) { return null; }
        public Long getCount() { return null; }
    }
    
    

8.3 RedisTemplate(掌握)

8.3.1 环境准备(使用redis)
  1. 开启Redis服务

    注意

    • 要求启动时使用的配置文件中绑定可以从外部连通的本机网卡地址、禁用受保护模式。否则启动会报错
    bind 192.168.115.130
    prot 6379
    protected-mode no
    
  2. 导入Jedis依赖坐标

    <!-- Jedis  -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>
    
  3. 创建Jedis对象,并使用

    public class App {
        public static void main(String[] args) {
            Jedis jedis = new Jedis("192.168.115.130",6379);
            jedis.set("name","company");
            jedis.close();
        }
    }
    
    
8.3.2 使用RedisTemplate
  • 导入依赖坐标

    <!-- Spring-Context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    
    <!-- junit单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    
    <!-- Spring整合junit -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    
    <!-- Spring-data-redis 内含RedisTemplate -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>2.0.6.RELEASE</version>
    </dependency>
    
    <!-- jedis,被Spring-redis依赖 -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>
    </dependencies>
    
  • Redis配置文件

    # redis服务器主机地址
    redis.host=192.168.115.130
    #redis服务器主机端口
    redis.port=6379
    
    #redis服务器登录密码
    #redis.password=company
    
    #最大活动连接
    redis.maxActive=20
    #最大空闲连接
    redis.maxIdle=10
    #最小空闲连接
    redis.minIdle=0
    #最大等待时间
    redis.maxWait=-1
    
  • RedisTemplate装配进Spring容器

    Redis配置类:ReidsConfig.java

    @PropertySource("redis.properties")
    public class RedisConfig {
    
        @Value("${redis.host}")
        private String hostName;
    
        @Value("${redis.port}")
        private Integer port;
    
    //    @Value("${redis.password}")
    //    private String password;
    
        @Value("${redis.maxActive}")
        private Integer maxActive;
        @Value("${redis.minIdle}")
        private Integer minIdle;
        @Value("${redis.maxIdle}")
        private Integer maxIdle;
        @Value("${redis.maxWait}")
        private Integer maxWait;
    
    
    
        @Bean
        //配置RedisTemplate
        public RedisTemplate createRedisTemplate(RedisConnectionFactory redisConnectionFactory){
            //1.创建对象
            RedisTemplate redisTemplate = new RedisTemplate();
            //2.设置连接工厂
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            //3.设置redis生成的key的序列化器,对key编码进行处理
            RedisSerializer stringSerializer = new StringRedisSerializer();
            redisTemplate.setKeySerializer(stringSerializer);
            redisTemplate.setHashKeySerializer(stringSerializer);
            //4.返回
            return redisTemplate;
        }
    
        @Bean
        //配置Redis连接工厂
        public RedisConnectionFactory createRedisConnectionFactory(RedisStandaloneConfiguration redisStandaloneConfiguration,GenericObjectPoolConfig genericObjectPoolConfig){
            //1.创建配置构建器,它是基于池的思想管理Jedis连接的
            JedisClientConfiguration.JedisPoolingClientConfigurationBuilder builder = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
            //2.设置池的配置信息对象
            builder.poolConfig(genericObjectPoolConfig);
            //3.创建Jedis连接工厂
            JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration,builder.build());
            //4.返回
            return jedisConnectionFactory;
        }
    
        @Bean
        //配置spring提供的Redis连接池信息
        public GenericObjectPoolConfig createGenericObjectPoolConfig(){
            //1.创建Jedis连接池的配置对象
            GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
            //2.设置连接池信息
            genericObjectPoolConfig.setMaxTotal(maxActive);
            genericObjectPoolConfig.setMinIdle(minIdle);
            genericObjectPoolConfig.setMaxIdle(maxIdle);
            genericObjectPoolConfig.setMaxWaitMillis(maxWait);
            //3.返回
            return genericObjectPoolConfig;
        }
    
    
        @Bean
        //配置Redis标准连接配置对象
        public RedisStandaloneConfiguration createRedisStandaloneConfiguration(){
            //1.创建Redis服务器配置信息对象
            RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
            //2.设置Redis服务器地址,端口和密码(如果有密码的话)
            redisStandaloneConfiguration.setHostName(hostName);
            redisStandaloneConfiguration.setPort(port);
    //        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
            //3.返回
            return redisStandaloneConfiguration;
        }
    }
    

    Spring核心配置类:SpringConfig.java

    // @Configuration
    @ComponentScan("com.company")
    @Import(RedisConfig.class)
    public class SpringConfig {
    }
    
  • 业务层注入并使用RedisTemplate

    @Service("accountService")
    public class AccountServiceImpl implements AccountService {
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        public void save(Account account) {
        }
    
        public void changeMoney(Integer id, Double money) {
            //等同于redis中set account:id:1 100
            redisTemplate.opsForValue().set("account:id:"+id,money);
        }
    
        public Double findMondyById(Integer id) {
            //等同于redis中get account:id:1
            Object money = redisTemplate.opsForValue().get("account:id:" + id);
            return new Double(money.toString());
        }
    }
    
  • 测试类

    //设定spring专用的类加载器
    @RunWith(SpringJUnit4ClassRunner.class)
    //设定加载的spring上下文对应的配置
    @ContextConfiguration(classes = SpringConfig.class)
    public class AccountServiceTest {
        @Autowired
        private AccountService accountService;
    
        /*@Test
        public void test(){
            Jedis jedis = new Jedis("192.168.40.130",6378);
            jedis.set("name","company");
            jedis.close();
        }*/
    
        @Test
        public void save(){
            Account account = new Account();
            account.setName("Jock");
            account.setMoney(666.66);
    
        }
    
        @Test
        public void changeMoney() {
            accountService.changeMoney(1,200D);
        }
    
        @Test
        public void findMondyById() {
            Double money = accountService.findMondyById(1);
            System.out.println(money);
        }
    }
    

9. 相关设计模式

设计模式:在不断的编码摸索过程中,总结出来的解决某些需求的思路(解决方案)

  • 策略模式,根据不同的条件,提供了多种解决方案供使用者选择,并最终解决问题。

    JDBCTemplate在封装结果集的时候,让使用者根据结果集字段名和实体属性名是否一致,选择手动封装或自动封装

  • 装饰者模式

    静态代理。

    目标对象:JDBCTemplate

    代理对象{ NamedParamterJDBCTemplate(从使用?作为占位符 增强成了 使用:名称作为占位符)

    ​ //持有目标对象,并且增强目标对象

    }

4ClassRunner.class)
//设定加载的spring上下文对应的配置
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountService accountService;

  /*@Test
  public void test(){
      Jedis jedis = new Jedis("192.168.40.130",6378);
      jedis.set("name","company");
      jedis.close();
  }*/

  @Test
  public void save(){
      Account account = new Account();
      account.setName("Jock");
      account.setMoney(666.66);

  }

  @Test
  public void changeMoney() {
      accountService.changeMoney(1,200D);
  }

  @Test
  public void findMondyById() {
      Double money = accountService.findMondyById(1);
      System.out.println(money);
  }

}






## 9. 相关设计模式

**设计模式**:在不断的编码摸索过程中,总结出来的解决某些需求的思路(解决方案)

- 策略模式,根据不同的条件,提供了多种解决方案供使用者选择,并最终解决问题。

`JDBCTemplate`在封装结果集的时候,让使用者根据结果集字段名和实体属性名是否一致,选择手动封装或自动封装

- 装饰者模式

静态代理。

目标对象:JDBCTemplate

代理对象{	NamedParamterJDBCTemplate(从使用`?`作为占位符 增强成了  使用`:名称`作为占位符)

​	//持有目标对象,并且增强目标对象

}









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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值