Spring框架技术总结

Posted 生命是有光的

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架技术总结相关的知识,希望对你有一定的参考价值。

0、目录总览

1、Spring JdbcTemplate

1.1、JdbcTemplate概述

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

1.2、JdbcTemplate开发步骤

  1. 导入 spring-jdbc 和 spring-tx 坐标
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>
  1. 创建数据库account表和Account实体

public class Account{
    private String name;
    private double money;
    //省略get和set方法
}
  1. 创建 JdbcTemplate 对象

  2. 执行数据库操作

//测试jdbcTemplate开发步骤
@Test
public void test1() throws Exception {
    //1.创建数据源对象
    ComboPooledDataSource dataSource = new ComboPooledDataSource();
    dataSource.setDriverClass("com.mysql.jdbc.Driver");
    dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
    dataSource.setUser("root");
    dataSource.setPassword("123456");
    //2.创建JdbcTemplate对象
    JdbcTemplate jdbcTemplate = new JdbcTemplate();
    //3.设置数据源给JdbcTemplate
    jdbcTemplate.setDataSource(dataSource);
    //4.执行操作
    jdbcTemplate.update("insert into account value(?,?)","tom",5000);
}

1.3、Spring产生JdbcTemplate对象

  • 我们可以将JdbcTemplate 的创建权交给 Spring,将数据源 DataSource的创建权也交给Spring
  • 在Spring容器内部将数据源DataSource 注入到JdbcTemplate 模板对象中
  • 配置如下:
<!--    数据源DataSource-->
<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>
<!--    JdbcTemplat -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>
  • 从容器中获得JdbcTemplate进行添加操作
@Test
public void test2(){
    ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    JdbcTemplate jdbcTemplate = app.getBean(JdbcTemplate.class);
    jdbcTemplate.update("insert into account value(?,?)","tom",5000);
}

1.4、解耦配置

我们在配置数据源和 JdbcTemplate 时,可以将配置文件进行解耦抽取

  • 在资源目录下新建jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
  • 修改spring核心配置文件,加载properties
    • 需要引入 context 命名空间
<?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">

<!--    加载外部的properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
    
<!--    数据源DataSource-->
<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>
<!--    JdbcTemplat -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>

2、JdbcTemplate常用操作

2.1、修改

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateCRUDTest {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Test
    //测试修改操作
    public void testUpdate(){
        jdbcTemplate.update("update account set money=? where name = ?",1000,"tom");
    }
}

2.2、删除

@Test
public void testDelete(){
    jdbcTemplate.update("delete from account where name=?","tom");
}

2.3、查询

2.3.1、查询全部

@Test
public void testQueryAll(){
    List<Account> accounts = jdbcTemplate.query("select * from account",new BeanPropertyRowMapper<Account>(Account.class));
    for(Account account:accounts){
        System.out.println(account.getName());
    }
}

2.3.1、查询单个数据

@Test
//测试查询单个对象操作
public void testQueryOne(){
    Account account = jdbcTemplate.queryForObject("select * from account where name=?",new BeanPropertyRowMapper<Account>(Account.class),"tom");
    System.out.println(account.getName());
}

@Test
//测试查询单个简单数据操作(聚合查询)
public void testQueryCount(){
    Long count = jdbcTemplate.queryForObject("select count(*) from account",Long.class);
    System.out.println(count);
}

2.4、知识要点

  1. 创建JdbcTemplate对象
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
  1. 更新操作
jdbcTemplate.update(sql,params);
  1. 查询操作
jdbcTemplate.query(sql,Mapper,params);
jdbcTemplate.queryForObject(sql,Mapper,params);

3、Spring事务

3.1、事务回顾

事务:保证一组数据库的操作,要么同时成功,要么同时失败

3.2、四大特性

  • 隔离性

    多个事务之间要相互隔离,不能互相干扰

  • 原子性

    指事务是一个不可分割的整体,类似一个不可分割的原子

  • 一致性

    保障事务前后这组数据的状态是一致的。要么都是成功的,要么都是失败的。

  • 持久性

    指事务一旦被提交,这组操作修改的数据就真的的发生变化了。即使接下来数据库故障也不应该对其有影响。

3.3、事务的隔离级

  • 脏读:允许读取未提交的信息

    • 原因:Read uncommitted

    解决方案: (表级读锁)

  • 不可重复读:读取过程中单个数据发生了变化
    • 解决方案: Repeatable read (行级写锁)

  • 幻读:读取过程中数据条目发生了变化
    • 解决方案: Serializable(表级写锁)

3.4、事务管理

Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以
使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。

3.5、事务控制方式

  • 编程式

  • 声明式(XML)

  • 声明式(注解)

编程式事务管理

  • 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
  • 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码

声明式事务管理

  • 一般情况下比编程式事务好用
  • 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
  • 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务
    管理。

3.6、事务管理器

  • 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。

  • 就是 Spring的核心事务管理抽象,管理封装了一组独立于技术的方法。

<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

4、实现声明式事务

  1. 什么是声明式事务控制?
  • Spring 的声明式事务顾名思义就是采用声明的方式来处理事务
  • 这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。

Spring 声明式事务控制底层就是AOP

只要简单的加个注解(或者是xml配置)就可以实现事务控制,不需要事务控制的时候只需要去掉相应的注解即可。

4.1、案例环境准备

  1. sql语句准备

CREATE DATABASE /*!32312 IF NOT EXISTS*/`spring_db` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `spring_db`;
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) DEFAULT NULL,
  `money` DOUBLE DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT  INTO `account`(`id`,`name`,`money`) VALUES 
(1,'三更',100),
(2,'草堂',100);
  1. 创建实体类
    • com.sangeng.domain.Account.java
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Account {
    private Integer id;
    private String name;
    private Double money;
}
  1. 数据持久层接口和对应xml文件
    • com.sangeng.dao.AccountDao
public interface AccountDao {
    public void updateMoney(@Param("id") Integer id, @Param("updatemoney") Double updatemoney);
}

resourecs/com/sangeng/dao.AccountDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sangeng.dao.AccountDao">

    <update id="updateMoney" >
        update account set money = money + #{updatemoney} where id = #{id}
    </update>

</mapper>
  1. 业务层接口和实现类
    • com.sangeng.service.AccountService
    • com.sangeng.service.impl.AccounttServiceImpl
public interface AccountService {
    /**
     * 转账
     * @param outId 转出账户的id
     * @param inId  转入账户的id
     * @param money 转账金额
     */
    public void transfer(Integer outId,Integer inId,Double money);
}
@Service
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountDao accountDao;

    @Override
    public void transfer(Integer outId, Integer inId, Double money) {
        //增加
        accountDao.updateMoney(inId,money);
        //减少
        accountDao.updateMoney(outId,-money);

    }
}
  1. spring整合mybatis
<?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">
<!--    组件扫描,扫描com.sangeng包下的所有注解-->
    <context:component-scan base-package="com.sangeng"></context:component-scan>
<!--    读取properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--   创建连接池注入容器-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <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 class="org.mybatis.spring.SqlSessionFactoryBean" id="sessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
<!--        配置mybatis配置文件的路径-->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
    </bean>

    <!--mapper扫描配置,扫描到的mapper对象会被注入Spring容器中-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer">
        <property name="basePackage" value="com.sangeng.dao"></property>
    </bean>
</beans>
  1. mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>


</configuration>
  1. 测试类
    • test.java.com.sangeng.AccountTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext.xml")
public class AccountTest {

    @Autowired
    private AccountService accountService;

    @Test
    public void testTransfer(){
        accountService.transfer(1,2,new Double(10));
    }
}

4.2、注解实现声明式事务

@Service
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountDao accountDao;

    @Override
    public void transfer(Integer outId, Integer inId, Double money) {
        //增加
        accountDao.updateMoney(inId,money);
        int i = 1/0; //手动制造错误
        //减少
        accountDao.updateMoney(outId,-money);

    }
}

如果我们在业务层实现类出现错误,那么就会造成转入钱增加,但是因为执行不到后续代码,会造成转出的钱没有减少,解决方法就是在业务层实现类增加事务。

4.2.1、导入依赖

因为声明式事务底层是通过AOP实现的,所以最好把AOP相关依赖都加上。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

4.2.2、配置事务管理器和事务注解驱动

在spring的配置文件中添加如下配置:

以上是关于Spring框架技术总结的主要内容,如果未能解决你的问题,请参考以下文章

spring框架的一些技术总结

Spring框架技术总结

SpringMVC框架技术总结

SpringMVC框架技术总结

万字Spring框架学习总结(附核心代码详细注释)

万字Spring框架学习总结(附核心代码详细注释)