Day49-Spring-03 - AOP开发(注解方式)-JDBC模板- 事务管理

一、AOP注解(注解方式)

 在Spring02中讲述了xml方式的aop,现在讲解aop的注解形式。
  1. 导入jar包
    四个基本包
    Spring包下:spring-aop-4.2.9.RELEASE.jar,spring-aspects-4.2.9.RELEASE.jar
    相关jar包:aopalliance-1.0.jar,aspectjweaver-1.8.9.jar
    (和aop的xml方式导入的jar包一样)

  2. 导入约束
    导入AOP的约束

  3. 在xml中打开aop的自动代理开关,同时增强类和业务逻辑类也是必须的
    如果是IOC的注解,采用context:component-scan来打开
    如果是AOP的注解:采用aop:aspectj-autoproxy

           <bean id="us" class="com.itheima.service.impl.UserServiceImpl" ></bean>
            <bean id="logger" class="com.itheima.util.Logger" ></bean>

           <!--  扫描开关打开有两种:

               如果是IOC的注解, 采用context : conponent-scan 开关去打开
               如果是AOP的注解 , 采用aop:    aop:aspectj-autoproxy
           -->

           <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  1. 在增强类中打上注解。
        @Aspect //表示我们这个Logger类是一个切面增强类。 
        public class Logger {

            @Before("execution(* com.itheima.service.*.*(..))")
            public static void log(){
                System.out.println("输出日志了~~");
            }
        }

二、 JDBC模板

Spring 由于所处的位置比较尴尬,刚好处在三层的中间位置。 它除了弄好自己的IOC + AOP之外, 为了更好的推广自己,让自己的生命力变得更持久, 也对持久层的框架做出了支持。 说白了,就是包装了dao层的框架代码。让程序员编程效率更高点。

    对持久化框架的支持有以下几个
    如果dao层采用的是JDBC来实现,那么spring会提供 JDBC模板
    如果dao采用的是hibernate来实现,那么spring也会随之提供hibernate模板
    Mybatis也是如此.. 

1. jdbc模板 入门 – 以向数据库插入数据为例子

  1. 导入jar包
    额外导入 三个jar包
    spring-jdbc-xxx.jar
    spring-tx-xxx.jar (事务的包)
    jdbc的驱动包

  2. 写代码
    如何写这段代码:
    只需要记住一个关键的类名:JdbcTemplate即可,后续可以通过这个类,添加响应的dataSource,然后进行插入

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///user");
        dataSource.setUsername("root");
        dataSource.setPassword("root");

        //1. 创建jdbc模板实例  和dbutils挺像的。 操作数据库,也是两个方法。
        JdbcTemplate jdbcTemplate = new JdbcTemplate();

        //设置数据源
        jdbcTemplate.setDataSource(dataSource);

        String sql = "insert into t_user values (null , ? , ?)";
        jdbcTemplate.update(sql, "admin","admin");

2. jdbc模板 CRUD

jdbc模板针对查询的操作,稍微要注意下即可,需要我们手动封装数据。

  • insert
       DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///user");
        dataSource.setUsername("root");
        dataSource.setPassword("root");

        //1. 创建jdbc模板实例  和dbutils挺像的。 操作数据库,也是两个方法。
        JdbcTemplate jdbcTemplate = new JdbcTemplate();

        //设置数据源
        jdbcTemplate.setDataSource(dataSource);

        String sql = "insert into t_user values (null , ? , ?)";
        jdbcTemplate.update(sql, "admin","admin");
  • delete
     @Test
      public void test01(){
           DriverManagerDataSource dataSource = new DriverManagerDataSource();
            //dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/db_for_test");
           dataSource.setUsername("root");
           dataSource.setPassword("123456");

           JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

           String sql = "delete from user where id = ?";
           jdbcTemplate.update(sql, 6);

      }
  • update
     @Test
      public void test02(){
           DriverManagerDataSource dataSource = new DriverManagerDataSource();
            //dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/db_for_test");
           dataSource.setUsername("root");
           dataSource.setPassword("123456");

           JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

           //String sql = "insert into user values(null,?,?)";
           String sql = "update user set address = ? where id = ?";
           jdbcTemplate.update(sql,"地球",5);

      }
  • 查询总条数 - 稍微麻烦一点,功能没有JDBC强,勉强可用
    JdbcTemplate这个类进行查询的时候,不会将结果封装成为我们需要的对象,需要我们手动进行封装

  • 查询总记录条数

      @Test
      public void test03(){
           DriverManagerDataSource dataSource = new DriverManagerDataSource();
            //dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/db_for_test");
           dataSource.setUsername("root");
           dataSource.setPassword("123456");

           JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

           String sql = "select count(*) from user";
           int result = jdbcTemplate.queryForObject(sql, Integer.class);
           System.out.println(result);
      }
  • 查询单个对象
      @Test
      public void test04(){
           DriverManagerDataSource dataSource = new DriverManagerDataSource();
            //dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/db_for_test");
           dataSource.setUsername("root");
           dataSource.setPassword("123456");

           JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

           String sql = "select * from user where id = ?";
           User result = jdbcTemplate.queryForObject(sql, new MyRowMapper(),5);
           System.out.println(result);
      }

      class MyRowMapper implements RowMapper<User> {
           @Override
           public User mapRow(ResultSet paramResultSet, int paramInt) throws SQLException {
                 int id = paramResultSet.getInt("id");
                 String name = paramResultSet.getString("name");
                 String address = paramResultSet.getString("address");

                 User user = new User();
                 user.setAdd(address);
                 user.setName(name);
                 return user;
           }

      }
  • 查询list集合
    为什么不用jdbcTemplate.queryforList()方法呢?因为里面没有RowMapper这个参数
      @Test
      public void test04(){
           DriverManagerDataSource dataSource = new DriverManagerDataSource();
            //dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/db_for_test");
           dataSource.setUsername("root");
           dataSource.setPassword("123456");

           JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

           String sql = "select * from user";
           List<User> list= jdbcTemplate.query(sql, new MyRowMapper());
           System.out.println(list);
      }

      class MyRowMapper implements RowMapper<User> {

           @Override
           public User mapRow(ResultSet paramResultSet, int paramInt) throws SQLException {
                 int id = paramResultSet.getInt("id");
                 String name = paramResultSet.getString("name");
                 String address = paramResultSet.getString("address");

                 User user = new User();
                 user.setAdd(address);
                 user.setName(name);
                 return user;
           }

      }

3. jdbc模板 注入写法 – 使用测试整合UserService - UserDao - JDBCTemplate - C3p0连接池

导包:
导入Spring四个核心jar包,Spring-jdbc-xx.jar ,Spring-tx-xxx.jar, jdbc驱动, Spring-test-xxx.jar

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class testSpring模板整合service层和dao层 {

      @Autowired
      private UserService userService;


      @Test
      public void test01(){

           userService.save();
      }

}
  • service代码
@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() {
                String sql = "insert into t_user values (null , ? , ?)";
                jdbcTemplate.update(sql, "zhangsan","123456");
                System.out.println("保存完毕~");
            }
        }
  • 配置
       <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"
            scope="prototype">
            <property name="userDao" ref="userDao"></property>
        </bean>

        <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
            <!-- ref : 告诉spring要new哪一个类给注入进去 要想表示这个类, 得声明一个bean -->
            <property name="jdbcTemplate" ref="jt"></property>
        </bean>


        <bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="ds"></property>
        </bean>

        <bean id="ds" 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>

4. jdbc模板 关联c3p0连接池

优化使用:使用c3p0来优化上面案例的模板的使用

代码不用改动,只要改动注入的数据源即可
首先导入c3p0连接池的jar包
配置文件:

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

    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
      <property name="userDao" ref="userDao"></property>
    </bean>
    <bean id="userDao" class="com.itheima.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="com.mchange.v2.c3p0.ComboPooledDataSource">
      <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
      <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_for_test"></property>
      <property name="user" value="root"></property>
      <property name="password" value="123456"></property>
    </bean>


    <context:component-scan base-package="com.itheima"></context:component-scan>

</beans>

三、事务

  • 什么是事务

事务其实就是用来包装一组逻辑,控制逻辑的整体结果。 如果这一组逻辑里面有一个动作执行失败, 那么整组的结果就以失败告终。(回滚事务) , 如果这一组逻辑里面运行都成功了,那么就认为成功(提交事务)

  • 事务特性

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

  • 事务如果不考虑隔离会出现以下问题

    • 读问题
      脏读
      不可重复读
      虚读|幻读

      隔离级别:
      读未提交
      读已提交 : Oracle
      可重复读 : Mysql
      序列化|串行化

    • 写问题
      丢失更新
      两个事务同时操作。 不管后面的那个事务是提交还是回滚,都将让前一个事务提交的结果,失效。丢失。

      乐观锁
      认为不会出现丢失更新, 要在表里面加一个字段,自己维护。
      悲观锁
      还没开始做,就认为一定会丢失更新。
      在开始操作之前,先执行查询 for update

1. 编程式

导包:
Spring-jdbc-XXX.jar
Spring-tx-xxx.jar
当然还有jdbc驱动包
主要的类就是TransactionTemplate和JdbcTemplate

        @Test
        public void testDemo(){
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///user");
            dataSource.setUsername("root");
            dataSource.setPassword("root");


            //定义事务的管理者
            DataSourceTransactionManager transactionManager  =  new DataSourceTransactionManager(dataSource);

            //创建事务的模板
            TransactionTemplate transactionTemplate = new TransactionTemplate();
            //设置事务的管理者是谁。一定要设置管理者,否则无法使用事务。
            transactionTemplate.setTransactionManager(transactionManager);


            final JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);

            //设置回调,也就是在里面写我们真正要操作的 crud逻辑
            transactionTemplate.execute(new TransactionCallback<Object>() {

                @Override
                public Object doInTransaction(TransactionStatus arg0) {

                    try {
                        //在这里面写 crud代码。 这个doInTransaction 方法会被spring的框架所调用。
                        //它在底下开启完事务之后,就用这个方法。

                        String sql = "insert into t_user values (null , ? , ?)";
                        jdbcTemplate.update(sql , "aobama2","6666222");

                        int a = 10 / 0 ;
                    } catch (DataAccessException e) {
                        e.printStackTrace();

                        //设置回滚的标记。
                        arg0.setRollbackOnly();
                    }
                    return null;
                }
            });
        }

2. 声明式 - XML

  1. 导入jar包
    Spring-jdbc-XXX.jar
    Spring-tx-xxx.jar
    当然还有jdbc驱动包
  2. 导入约束
    aop \ tx \bean 约束

  3. 配置事务
    可以看出,事务的本质也是进行了aop的增强,在前面加上了事务的开启,后面加上了事务的提交和回滚

        <!-- 以下是配置事务  事务的配置,其实就是AOP的操作。 -->
        <!-- 1. 声明事务的建议  会对哪一个方法进行事务啊。 就是在这里进行配置-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="ds"></property>
        </bean>



        <tx:advice id="advice" transaction-manager="transactionManager">
            <!-- 这个tx:attributes 就是用来控制到底给哪个方法加入事务 -->
            <tx:attributes>
                <!-- * 表示给前面找到的所有方法都应用事务  dao ==== jdbctemplate    hibernatetemplate-->
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>



        <!-- 还少一件事情, 对哪些类的,哪些方法,进行事务。 -->
        <aop:config>
            <aop:pointcut expression="execution(* com.itheima.service.*.*(..))" id="pointCut"/>

            <!-- 给上面的pointCut 切入点,找到的方法,应用上面给出的事务建议。也就是给这些方法,都是用事务来管理 -->
            <aop:advisor advice-ref="advice" pointcut-ref="pointCut"/>
        </aop:config>

3. 声明式 - 注解(重要 - 最常用的方式)

  1. 在xml里面指定事务使用的管理者是谁
         <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
      <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_for_test"></property>
      <property name="user" value="root"></property>
      <property name="password" value="123456"></property>
    </bean>

         <!-- 打开注解开关  这里是指定注解的事务,采用什么管理者。 光有那个类上的注解,是不够的,因为spring
         也不知道我们打算使用什么类型的管理者来操作事务。 -->
         <tx:annotation-driven transaction-manager="transactionManager"/>

2. 在业务逻辑类上面打上注解 ,当然如果想指定具体的某一个方法采用事务,也可以在方法上面打上注解


public class UserDaoImpl implements UserDao {

      private JdbcTemplate jdbcTemplate;
      public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
           this.jdbcTemplate = jdbcTemplate;
      }

      @Override
      @Transactional
      public void save() {
           System.out.println("userDao的save方法执行了");
           String sql = "insert into user values(null,?,?)";
           jdbcTemplate.update(sql, "测试1","测试1");
           int i= 10/0;
           jdbcTemplate.update(sql, "测试2","测试2");
           System.out.println("保存成功");
      }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值