Spring入门(三)— AOP注解、jdbc模板、事务

一、AOP注解开发

  1. 导入jar包

    aop联盟包、 aspectJ实现包 、 spring-aop-xxx.jar 、 spring-aspect-xxx.jar

  2. 导入约束

    aop约束

  3. 托管扩展类和被扩展类
  <!-- 要做AOP, 一定要托管扩展类和被扩展类 -->
   <bean id="us" class="com.pri.service.impl.UserServiceImpl"></bean>
   <bean id="logger" class="com.pri.util.Logger"></bean>   
也可以使用注解来托管这两个类 。  @Component
  1. 在扩展出来的功能类身上和方法上打注解
@Aspect //这个注解,是和aop有关,用于表示该类是一个功能扩展类,专门用来做增强的。
public class Logger {
    @Before("execution(* com.pri.service.impl.*.*(..))")
    public void log(){
        System.out.println("输出日志了~~~!");
    }
}

二、 Jdbc模板

  • 为什么spring也要提供jdbc模板呢?

spring是属于service层的框架, 它所处的位置比较尴尬,并且它想让自己更受程序员的喜爱。 除了能够做好自己的核心 IOC & AOP , 它还对前后两个框架都提供了支持。 spring其实对dao层的大部分技术有提供模板支持 。

1. jdbc模板的入门

public void testDemo(){

        //数据源,连数据库。 连什么类型的数据, 哪个库, 账号 & 密码
        DriverManagerDataSource dataSource  =new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///stus");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
?
        //1. 创建jdbc模板
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);

        String sql = "insert into t_user values(null , ? , ? )";

        //2. 执行添加操作,其实它的用法和以前的queryrunner一样。
        jdbcTemplate.update(sql , "66666","zhangsan");
}

2. crud操作

  • insert
String sql = "insert into t_user values (null , ? , ?)";
jdbcTemplate.update(sql, "heima24","6666");
  • delete
 @Test
 public void testDelete(){
      //3. 执行添加操作
      String sql = "delete from t_user where uid = ?";
      jdbcTemplate.update(sql, 11);
 }
  • udpate
@Test
public void testUpdate(){
      //3. 执行添加操作
      String sql = "update t_user set password=? where uid=?";
      jdbcTemplate.update(sql, "888",11);
}
  • findCount
@Test
public void testFindCount(){
     //3. 执行添加操作
     String sql = "select count(*) from t_user";
     int count = jdbcTemplate.queryForObject(sql, Integer.class);
     System.out.println("count="+count);
}
  • findObject
@Test
public void testFindObject(){
       //3. 执行添加操作
      String sql = "select * from t_user where uid = ?";
      User user = jdbcTemplate.queryForObject(sql,new MyRowMapper()  , 10);
      System.out.println("user="+user);
}
  • findList
@Test
public void testFindList(){
     //3. 执行添加操作
     String sql = "select * from t_user ";
     List<User> user = jdbcTemplate.query(sql, new MyRowMapper());
     System.out.println("user="+user);
}

查询要求我们手动封装class MyRowMapper implements RowMapper<User>{

@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {

        System.out.println("arg1=="+arg1);

        User user = new User();
        user.setUid(rs.getInt("uid"));
        user.setUsername(rs.getString("username"));
        user.setPassword(rs.getString("password"));
        return user;
    }
}

3. jdbc模板的注入写法

该小节演练的是三层结构的所有属性注入写法。(不写action | servlet)

1. 分析

以下代码其实是位于dao层的

  @Override
    public void save(User user) {
?
        // 数据源,连数据库。 连什么类型的数据, 哪个库, 账号 & 密码
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///stus");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
?
        // 1. 创建jdbc模板
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
?
        String sql = "insert into t_user values(null , ? , ? )";
?
        // 2. 执行添加操作,其实它的用法和以前的queryrunner一样。
        jdbcTemplate.update(sql, user.getPassword(), user.getUsername());
    }

这套代码很多,而且它只是一个dao的操作代码而已。 如果我们还有别的dao方法。也要执行数据库操作,那么必然也得写出来这样的代码。 那么就存在冗余代码了。

解决方案:

  1. 以前的解决方法:

    ? 工具类 | 静态代码块

    1. 现在学了spring了,我想用spring的手法来简化dao的这一套代码。

      ?分析以上代码,其实它就是做了两个工作。

      ?a. 创建了jdbc模板的对象,并且完成了属性的赋值工作。

      ?b. 创建了dataSource 的对象,并且完成了属性的赋值工作。

spring也可以完成这个工作, 创建对象,其实就是`IOC`的体现, 对属性的赋值工作其实就是`DI`的体现
?~~~xml
<bean id="jdbctemplate" class="">
    <property name="dataSource" ref="dataSource">

 <bean id="dataSource" class="">
    <property name="..." value="">
    <property name="..." value="">
    <property name="..." value="">
    <property name="..." value="">
?~~~

2. 基本实现

  • service
public class UserServiceImpl implements UserService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
         this.userDao = userDao;
    }
?
    @Override
    public void save() {
        System.out.println("调用了UserServiceImpl的save方法~~!");
?      userDao.save();
    }
}
  • dao
public class UserDaoImpl implements UserDao {
   private JdbcTemplate jdbcTemplate;
   public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
   }
   @Override
   public void save() {
        System.out.println("调用了UserDaoImpl的save方法~~");
        //3. 执行添加操作
        String sql = "insert into t_user values (null , ? , ?)";
        jdbcTemplate.update(sql, "heima242","0000");
?
    }
}
  • xml
<bean id="us" class="com.pri.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
</bean>
?
<bean id="userDao" class="com.pri.dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
?
<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 name="url" value="jdbc:mysql:///stus"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
</bean>

3. 整合c3p0连接池

  1. 导入jar包

c3p0-0.9.5.2.jar   mchange-commons-java-0.2.12.jar

  1. 在xml中配置
没有使用c3p0连接池的配置
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql:///user"></property>  <property name="username" value="root"></property>  <property name="password" value="root"></property></bean>
?
使用了c3p0的配置
<!-- 使用c3p0连接池 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
?  <property name="jdbcUrl" value="jdbc:mysql:///user"></property>  <property name="user" value="root"></property>  <property name="password" value="root"></property></bean>

4. 使用jdbc.properties记录数据库连接信息

为了方便修改数据库连接信息,通常在src下使用properties文件来记录他们。主要是方便修改

  1. 在src下新建一个properties文件,内容如下 名:jdbc.properties
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///user
user=root
password=root
  1. 在xml里面导入jdbc.properties ,并且在dataSource里面引用
a. 导入context约束
b. 导入jdbc.properties
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 使用c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
     <property name="driverClass" value="${driverClass}"></property>
     <property name="jdbcUrl" value="${jdbcUrl}"></property>
     <property name="user" value="${user}"></property>
     <property name="password" value="${password}"></property>
</bean>

三、 事务管理

1. 事务的回顾

  • 什么事务,事务有什么用?

事务是用于包装一组操作的。当这一组操作里面的所有步骤都执行成功,那么这一组操作就算成功(事务的提交),如果有哪一个步骤执行失败,那么这一组操作就以失败告终。(事务的回顾)

  • 事务的特性

原子性一致性隔离性持久性

  • 如果不考虑隔离级别,那么事务并发会出现以下问题
  1. 读的问题

    ? 脏读 : 读到了另一个事务还没有提交的数据

    ? 不可重复读 : 读到了另一个事务已经提交的数据 (针对的是update的数据)

    ? 虚读| 幻读 : 读到了另一个事务已经提交的数据(针对的是insert的数据)

    解决方案: 设置隔离级别

    ? 读未提交

    ? 读已提交 Oracle

    ? 可重复读 MySql

    ? 序列化|串行化

  2. 写的问题

    ? 丢失更新: 最后操作的事务,不管是提交还是回滚,都会让前一个是的数据丢失掉。

    解决方案:

    ? 悲观锁 : 还没开始就认为一定会丢失更新。

    ? 每一个事务在执行操作之前,先进行一次查询。 并且查询的语句里面带有关键字 for update

    ? 乐观锁 : 认为不会出现丢失更新,

    ? 要求程序员手动控制,给表额外添加一个字段 如: version。

2. Spring对事务的管理办法

  • 事务应该写在哪一层? 为什么spring也要插手管理事务?

事务应该写在Service层。 因为service表示的业务,一组业务可能会执行多个到的方法。所以在Service层声明事务更好一点。 而且spring正好是Service层的解决方案。

  • Spring针对事务的管理API

Spring 可以管理事务, 但是真正完成操作的技术,spring可不管。 dao层使用的技术可能有很多。 jdbchibernatemybatis . 但是这几个框架,他们开启事务的办法,可能不一样。 spring为了统一管理事务,声明了一套规范出来,并且对底下的使用频率比较到的技术,都给出了具体的实现。

?管理事务的规范是 : PlatformTransactionManager?    jdbc | mybatis : DataSourceTransactionManager    hibernate : HibernateTransactionManager?

spring对dao层使用什么技术,它不管,它统一规定,要操作事务,必须使用管理员!!!

3. spring对事务支持的写法

提供了三种写法 编程式事务声明式事务(xml & 注解)

1. 编程式事务

纯靠写代码来完成事务配置

@Test
public void test(){
    //事务的管理员是用来管理事务的,包含了打开事务、 提交事务、 回滚事务
    final DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql:///stus");
    dataSource.setUsername("root");
    dataSource.setPassword("root");

    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(dataSource);

    //1. 创建事务的模板对象。
    TransactionTemplate transactionTemplate = new TransactionTemplate();
    transactionTemplate.setTransactionManager(transactionManager);

    //事务事务的模板对象
    transactionTemplate.execute( new TransactionCallback<Object>() {
    //在事务里面执行这个方法。
    @Override
    public Object doInTransaction(TransactionStatus arg0) {
        //添加操作
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);

        String sql = "insert into  t_user values ( null , ? , ?)";
        jdbcTemplate.update(sql, "123","王五");
        int a = 1 / 0 ;
        jdbcTemplate.update(sql, "6666","赵六");
          return null;
       }
    });

}

2. 声明式事务(xml)

xml方式配置事务,其实就是使用AOP的思想,在方法执行前,开启事务,方法执行后,提交事务(回滚事务)

<!-- 以下属于事务的配置 如果要用事务了,那么事务的管理员是谁啊。 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
     <tx:advice id="advice01" transaction-manager="transactionManager">
        <tx:attributes>  <!-- 对前面的表达式找到的那一堆方法,进行过滤配置,表示谁才能用事务管理, 如果是* ,表示前面找到的那一堆都用事务管理 -->
            <tx:method name="save*"/>
            <tx:method name="update*"/>
            <tx:method name="delete*"/>
        </tx:attributes>
     </tx:advice>

     <!--
         以上配置,到目前为止,只是说明了,如果要开启事务,管理员是谁。 但是缺少了一个东西。
         就是哪一个方法到底要用事务呀? -->

     <aop:config>
        <aop:pointcut expression="execution(* com.pri.service.impl.*.*(..))" id="aa"/>

        <aop:advisor advice-ref="advice01" pointcut-ref="aa"/>
     </aop:config>

3. 声明式事务(注解)

使用注解的方式来开启事务

  • xml配置
1. 在xml中 声明注解事务的管理员
?
   <!-- 以下属于事务的配置 如果要用事务了,那么事务的管理员是谁啊。 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 指定注解事务使用的管理员是谁 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
  • 代码配置
2. 在业务逻辑类上或者方法上打注解?  类上的注解,表示类中的所有方法都用事务, 如果在方法上打注解,表示只有这个方法才会用事务
@Transactional
public class UserServiceImpl implements UserService {

}
?
public class UserServiceImpl implements UserService {
    @Transactional
    @Override
    public void save() {}
} 

原文地址:https://www.cnblogs.com/gdwkong/p/8453163.html

时间: 2024-12-11 10:35:07

Spring入门(三)— AOP注解、jdbc模板、事务的相关文章

Spring总结——AOP、JDBC和事务的总结

1.上一次总结了 Spring 的核心三大组件(Core,Beans,Context),今天总结的 AOP.JDBC和事务都可以看成是核心三大组件的应用. 其中 Spring 的事务管理又以 AOP 为基础的声明式事务管理,对 JDBC 数据操作进行了补充. 2.在学习 AOP 的时候,需要搞明白的几个问题. (1)AOP 是以动态代理为基础的,所以在学习 AOP 之前,首先对动态代理有深刻的理解. (2)AOP 和切面是什么关系. (3)AOP 中概念比较多,明白每个名词的含义:切面.增强.代

Spring入门篇——AOP基本概念

1.什么是AOP及实现方式 什么是AOP AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等 AOP实现方式 预编译 -ApectJ 运行期动态代理(JDK动态代理.CGLib动态代理) -SpringAOP.JbossAOP 2.AOP基本概念 连接点:比如一个类中某个方法执行的开始 通知:在某个方法执行的时候,额外执行的切面

spring中的aop注解(整合junit测试)

使用spring中的aop前先来了解一下spring中aop中的一些名词 Joimpoint(连接点):目标对象中,所有可能增强的方法 PointCut(切入点):目标对象,已经增强的方法 Advice(通知/增强):增强的代码 Target(目标对象):被代理对象 Weaving(织入):将通知应用到切入点的过程 Proxy(代理):将通知织入到目标对象之后,形成代理对象 aspect(切面):切入点+通知 一:不使用spring的aop注解 以javaEE中的service层为例 UserS

spring入门(二) 使用注解代替xml配置

1.导包(略) 2.applicationContext.xml如下: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:cont

Spring入门介绍-AOP(三)

AOP的概念 AOP是面向切面编程的缩写,它是一种编程的新思想.对我们经常提起的oop(面对对象编程)有一定的联系. AOP和OOP的关系 AOP可以说是oop的某一方便的补充,oop侧重于对静态的属性和方法组合为对象,使得逻辑更加清晰,而aop是是从动态角度考虑,处理过程中某个步骤或者阶段,是从动态角度考虑的. AOP的功能 主要处理事务,日志,安全,异常统计等功能. AOP的价值 AOP专门用于处理分布于各个各个模块中的交叉关注点的问题,在J2ee应用中.通常用AOP来处理一些具有横切性质的

Spring中的AOP注解方式和XML方式

应掌握内容:1. AOP的全名2. AOP的实现原理[静态代理和动态代理]3. 注解方式的配置4. 通知类型     A. 每种通知的特点和使用方式    B. 获取各种数据,方便日后操作5. 执行表达式的方式6. XML方式的配置7. 如何加载属性文件和注意事项8. 如何引入资源文件,为什么只用引入资源文件 AOP的概念: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是

Spring中的AOP注解方式和配置方式

今天学习了下spring中的切面编程:结合之前看过的视频.整合一下思路: 基本类: 接口: public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); } 接口的实现: import org.springframework.stereotype.Component; @Component("ar

Spring入门之AOP实践:@Aspect + @Pointcut + @Before / @Around / @After

零.准备知识 1)AOP相关概念:Aspect.Advice.Join point.Pointcut.Weaving.Target等. ref: https://www.cnblogs.com/zhangzongle/p/5944906.html  有代码示例 2)相关注解:@Aspect.@Pointcut.@Before.@Around.@After.@AfterReturning.@AfterThrowing 一.实践目标 1)@Aspect的功能 2)@Pointcut的切面表达式 3)

Spring笔记(三)AOP前篇之动态代理

AOP思想是将程序中的业务代码与服务代码进行分离,在运行时进行结合.比较强调程序的层次结构,是一种面向切面的编程.而在AOP实现的底层主要用到了动态代理,而动态代理又分为JDK动态代理和CGLIB动态代理,两者的区别是JDK动态代理的实现中业务类必须必须定义接口,而CGLIB没有这个约束,可以说CGLIB更强大: JDK动态代理实现示例: // 业务接口定义 public interface IUnit {     void execute(String msg); } // 业务实现类 pub

spring 技术(三) ----- AOP应用开发

1. 新建一个Java Project.名为springtest3.然后新建一个package.名为com.gxcme.springtest3. 2. 加入spring框架. 3.新建一个Interface.名为BankInterface.java. 4.新建一个class.名为BankImpl.java.继承BankInterface. 5.新建一个class.名为BankAdvice.java. 6. 新建一个class.名为BankMain.java. 7. 在applicationCon