SSM框架系列学习总结3之Spring DAO

在这里先把AOP的内容总结完毕!

SpringAOP的五种通知方式
  1. 后置通知: 执行目标对象业务方法之后执行服务代码
    2.方法正常返回通知:
    3.方法抛出异常通知:
    4.环绕通知:
    Spring配置

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd

           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           ">

    
    <bean id="userDao" class="com.wtu.spring.aop.before.UserDaoImpl">
    bean>

    
    <bean id="myLog" class="com.wtu.spring.aop.before.MyLog"/>

    
    <aop:config proxy-target-class="true">
        <aop:pointcut expression="execution(* com.wtu.spring.aop.before.UserDaoImpl.a*(..))" id="xxx"/>
       
        <aop:aspect ref="myLog">
            <aop:after method="writeConsole" pointcut-ref="xxx"/>
        aop:aspect>
    aop:config>

beans>

切面对象:

public class MyLog {
    @SuppressWarnings("deprecation")
    public void writeConsole() {
        System.out.println(new Date().toLocaleString());
    }
}

目标对象, 执行核心代码:

public class UserDaoImpl implements UserDao {

    @Override
    public void addUser() {

//        if (true) {
//            throw new RuntimeException("测试一下遇到异常执行情况");
//        }

        System.out.println("添加用户...");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

测试类:

        // 启动Ioc容器
        ApplicationContext ac = new ClassPathXmlApplicationContext(
                new String[]{"com/wtu/spring/aop/before/spring3.0.xml"}
        );

        UserDao userDao = (UserDao) ac.getBean("userDao");
        userDao.addUser();

        System.out.println(userDao.getClass());
        //class com.wtu.spring.aop.before.UserDaoImpl$$EnhancerByCGLIB$$aa48c241

运行结果:
SSM框架系列学习总结3之Spring DAO_第1张图片

SpringAOP环绕通知

环绕通知默认情况下代理对象只会调用一次服务代码,连目标对象的业务方法都不会调用。
因此, 我们需要借助一个类, 去手动调用
ProceedingJoinPoint :使用该类的一个对象作为切面中方法的形式参数传入,再通过该对象的proceed()方法实现对目标对象方法的调用.
切面:

public class MyLog {
    /**
     * 环绕通知得在切面的方法中带上一个参数, 类型是ProceedingJoinPoint
     * 通过该对象proceed方法来调用目标对象的业务方法
     */
    @SuppressWarnings("deprecation")
    public void writeConsole(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println(new Date().toLocaleString());
        pjp.proceed(); // 相当于调用目标对象的切入点方法
        System.out.println(new Date().toLocaleString());
    }
}

Spring配置:

    
    <aop:config proxy-target-class="true">
        <aop:pointcut expression="execution(* com.wtu.spring.aop.around.UserDaoImpl.a*(..))" id="xxx"/>
        <aop:aspect ref="myLog">
            <aop:around method="writeConsole" pointcut-ref="xxx"/>
        aop:aspect>
    aop:config>

运行结果:

2018-1-21 12:47:58
增加用户...
2018-1-21 12:47:58

AOP 注解

首先是Spring的配置文件:(开启各种注解的功能)


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.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-3.0.xsd">

    
    <context:annotation-config/>
    
    <context:component-scan base-package="com.wtu.spring.aop.annotation"/>

    
    <aop:aspectj-autoproxy proxy-target-class="true"/>
beans>

切面:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 切面
 *
 * @Author menglanyingfei
 * @Created on 2018.01.17 17:06
 */
@Component
@Aspect
public class MyLog {
    /**
     * 环绕通知得在切面的方法中带上一个参数, 类型是ProceedingJoinPoint
     * 通过该对象proceed方法来调用目标对象的业务方法
     */
    @SuppressWarnings("deprecation")
    @Around(value = "execution(* com.wtu.spring.aop.annotation.UserDaoImpl.addUser(..))")
    public void writeConsole(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println(new Date().toLocaleString());
        pjp.proceed(); // 相当于调用目标对象的切入点方法
        System.out.println(new Date().toLocaleString());
    }

    @SuppressWarnings("deprecation")
    @Before(value = "execution(* com.wtu.spring.aop.annotation.UserDaoImpl.deleteUser(..))")
    public void writeConsole() throws Throwable {
        System.out.println(new Date().toLocaleString());
    }
}

目标对象的代码:

import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Repository;

/**
 * @Author menglanyingfei
 * @Created on 2018.01.17 15:01
 */
@Repository
public class UserDaoImpl implements UserDao {

    @Override
    @Pointcut
    public void addUser() {
        System.out.println("增加用户...");
    }

    @Override
    @Pointcut
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

SSM框架系列学习总结3之Spring DAO_第2张图片

SSM框架系列学习总结3之Spring DAO_第3张图片
SSM框架系列学习总结3之Spring DAO_第4张图片
SSM框架系列学习总结3之Spring DAO_第5张图片

AOP各种注解总结:
SpringAOP的注解形式:
@Aspect: 一般使用在切面的类名上面,作用是指定该类是一个切面
@PointCut:配置在目标对象的方法上面, 表示该方法是一个切入点
@Around @After @Before @After-returning @After-throwing
配置在切面的方法上面, 表示何种通知方式.

Spring DAO模块

Spring 数据访问, 因为Spring提供了对事务的支持!
所以, 我们首先来认识事务!

什么是DAO?

SSM框架系列学习总结3之Spring DAO_第6张图片

事务的基本概念

SSM框架系列学习总结3之Spring DAO_第7张图片

将一系列对数据库的操作进行捆绑,其中所有的操作要么全部执行成功, 要么全部执行不成功。
ACID特性
原子性 Atomicity
一致性 Consistency
隔离性 Isolation
持久性 Durability

Mysql中的事务

mysql会将一条sql语句当成是一个完整的事务!
Mysql中对事务操作:
start transaction – 开启事务
commit – 提交事务
rollback – 回滚事务

JDBC中对于事务的操作

对事务的管理在同一个Connection对象中
conn.setAutoCommit(false); jdbc中开启事务
conn.commit(); 提交事务
conn.rollback(); 回滚事务

代码示例:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @Author menglanyingfei
 * @Created on 2018.01.18 12:44
 */
public class TransactionTest {
    public static void main(String[] args) {
        /*
            JDBC中事务的使用
         */
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql:///spring_day03",
                    "root", "lxy");
            // 开启事务
            conn.setAutoCommit(false);
            // zhang给li转账500元
            String sql = "update account set balance = balance + ? where username=?";
            PreparedStatement pstmt = conn.prepareStatement(sql);

            // 给zhang减去500
            pstmt.setInt(1, -500);
            pstmt.setString(2, "zhang");
            pstmt.executeUpdate();

//            int i = 10 / 0;

            // 给li增加500
            pstmt.setInt(1, 500);
            pstmt.setString(2, "li");
            pstmt.executeUpdate();
            // 提交事务
            conn.commit();
        } catch (Exception e) {
            // 事务回滚
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }
    }
}
数据库并发访问时引起的问题

脏读
不可重复读
虚读/幻读
脏读.jpeg

SSM框架系列学习总结3之Spring DAO_第8张图片
SSM框架系列学习总结3之Spring DAO_第9张图片
SSM框架系列学习总结3之Spring DAO_第10张图片

1.脏读 一个事务读取了另一个事务未提交的数据 绝对不允许存在
2.不可重复读 : 一个事务对某一条记录的两次读取结果不一致,原因是另一个事务在两次读取期间对该记录进行了修改,Oracle数据库中就有这种问题, 对应数据库update操作
3.虚读/幻读: 一个事务对某一张表的两次读取结果不一致,原因是另一个事务在两次读取期间对该表进行了insert 或者 delete操作 mysql中就有这种问题

SSM框架系列学习总结3之Spring DAO_第11张图片

针对数据库并发访问的问题, 出现了隔离级别的概念
1.serializable 串行化 数据库不支持并发访问, 隔离级别最高,效率最低 不推荐使用
2.repeatable read 可重复读, mysql默认隔离级别
3.Read Commited 读已提交的数据, Oracle的默认隔离级别
4.Read uncommited 读未提交的数据, 出现脏读, 效率是最高的 但是不推荐使用

事务一般作用在javaWeb的service层.

Spirng DAO模块之Spring管理事务

Spring框架提供了一个事务管理类,通过该类来进行事务的管理
DataSourceTransactionManager

Spring中对事务的声明全部在配置文件中:
其中包括:
配置事务管理器
配置数据源
注册事务切面
配置aop代理


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.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-3.0.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    
    <bean id="userDao" class="com.wtu.spring.transaction.xml.UserDaoImpl"/>

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

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

    
    <tx:advice transaction-manager="dataSourceTransactionManager" id="xxx">
        <tx:attributes>
            
            <tx:method name="*" propagation="REQUIRED"/>
        tx:attributes>
    tx:advice>

    
    <aop:config proxy-target-class="true">
        
        <aop:pointcut id="pointId"
                 expression="execution(* com.wtu.spring.transaction.xml.UserDaoImpl.*(..))"/>
        <aop:advisor advice-ref="xxx" pointcut-ref="pointId"/>
    aop:config>
beans>

目标对象所在类:

public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("增加用户...");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户...");
    }
}

测试类:

public static void main(String[] args) {
        // 启动Ioc容器
        ApplicationContext ac = new ClassPathXmlApplicationContext(
                new String[]{"com/wtu/spring/transaction/xml/spring3.0.xml"}
        );

        UserDao userDao = (UserDao) ac.getBean("userDao");
        userDao.addUser();
    }

测试成功!
SSM框架系列学习总结3之Spring DAO_第12张图片

Spring DAO模块之Spring整合JDBC

Spring Dao模块提供了一个JDBC模板,那么通过这个模板操作数据库,有点类似于QueryRunner.
SSM框架系列学习总结3之Spring DAO_第13张图片

Spring的Dao模块提供了一个类JdbcTemplate:
该类中三个方法:
update(String sql, Object… args) 增删改
query(String sql, RowMapper rm, Object… args)
queryForObject 查询单个对象
其中的Spring配置:

    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_day03?characterEncoding=utf8"/>
        <property name="user" value="root"/>
        <property name="password" value="lxy"/>
    bean>

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

    
    <bean id="userDao" class="com.wtu.spring.dao.UserDaoImpl">
        <property name="jdbcTemplate" ref="jt"/>
    bean>

DAO数据操作类:

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @Author menglanyingfei
 * @Created on 2018.01.17 15:01
 */

public class UserDaoImpl implements UserDao {
    /*
        Spring的Dao模块提供了JdbcTemplate
        该类中三个方法:
        update(String sql, Object... args) 增删改
        query(String sql, RowMapper rm, Object... args)
        queryForObject 查询单个对象
     */
    private JdbcTemplate jdbcTemplate;

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

    @Override
    public void addUser(Customer customer) {
        String sql = "insert into `t_customer` values(?,?,?,?,?,?,?)";
        Object[] objects = {customer.getId(), customer.getName(), customer.getGender(),
            customer.getBirthday(), customer.getCellphone(), customer.getEmail(), customer.getDescription()};

        jdbcTemplate.update(sql, objects);
    }

    @Override
    public void deleteUser(String id) {
        System.out.println("删除用户");
    }

    /*
        查询单个对象, RowMapper是个接口
     */
    @Override
    public Customer findCustomer(String id) {
        String sql = "select * from `t_customer` where cid = ?";
        Object[] objects = {id};
        return jdbcTemplate.queryForObject(sql, new RowMapper() {
            /*
             * rs:查询结果集
             * rowNum: 表示当前结果集是第几行, 0表示第一行
             * 如果是单个对象, rowNum永远等于零
             * 下面这个方法表示循环遍历结果集, 也就是不需要我们再去写while循环
             */
            @Override
            public Customer mapRow(ResultSet rs, int i) throws SQLException {
                System.out.println("rowNum = " + i);
                //手工及解析结果集  封装Customer对象
                Customer c = new Customer();
                c.setId(rs.getString(1));
                c.setName(rs.getString(2));
                c.setGender(rs.getString(3));
                c.setBirthday(rs.getDate(4));
                c.setCellphone(rs.getString(5));
                c.setEmail(rs.getString(6));
                c.setDescription(rs.getString(7));
                return c;
            }

        }, objects);
    }

    @Override
    public List findAllCustomer() {
        String sql = "select * from `t_customer` ";

        return jdbcTemplate.query(sql, new RowMapper() {
            /*
             * rs:查询结果集
             * rowNum: 表示当前结果集是第几行, 0表示第一行
             * 如果是单个对象, rowNum永远等于零
             * 下面这个方法表示循环遍历结果集, 也就是不需要我们再去写while循环
             */
            @Override
            public Customer mapRow(ResultSet rs, int j) throws SQLException {
                System.out.println(j);

                //手工解析结果集  封装Customer对象
                Customer c = new Customer();
                c.setId(rs.getString(1));
                c.setName(rs.getString(2));
                c.setGender(rs.getString(3));
                c.setBirthday(rs.getDate(4));
                c.setCellphone(rs.getString(5));
                c.setEmail(rs.getString(6));
                c.setDescription(rs.getString(7));
                return c;
            }
        });
    }
}
SpringDao+事务: 通过注解形式

Spring配置:


<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"

        xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

          http://www.springframework.org/schema/aop
          http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

          http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_day03?characterEncoding=utf8"/>
        <property name="user" value="root"/>
        <property name="password" value="lxy"/>
    bean>

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

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

    
    <context:annotation-config/>

    
    <context:component-scan base-package="com.wtu.spring.dao.annotation"/>

    
    <aop:aspectj-autoproxy/>

    
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"
        proxy-target-class="true"/>
beans>

封装数据的实体类:

public class Customer {
    private String id;
    private String name;
    private String gender;
    private Date birthday;
    private String cellphone;
    private String email;
    private String description;
    // getter and setter omitted
}

dao数据操作类:

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @Author menglanyingfei
 * @Created on 2018.01.17 15:01
 */
/*
 * @Transactional加在类名上面: 表示该类中所有的方法都要加上事务
 * @Transactional:该注解一般写在service层中的实现类上
 */
//@Transactional
@Repository
public class UserDaoImpl implements UserDao {
    /*
        Spring的Dao模块提供了JdbcTemplate
        该类中3个方法:
        update(String sql, Object... args) 增删改
        query(String sql, RowMapper rm, Object... args) 查询所有
        queryForObject          查询单个对象
     */
    @Resource
    private JdbcTemplate jt;

    @Transactional
    @Override
    public void addUser(Customer c) {
        String sql = "insert into `t_customer` values(?,?,?,?,?,?,?)";
        Object[] obj = {c.getId(),c.getName(),c.getGender(),
                c.getBirthday(),c.getCellphone(),c.getEmail(),c.getDescription()};
        jt.update(sql, obj);
    }

    @Override
    public void deleteUser(String id) {
        System.out.println("删除用户");
    }

    /**
     * 查询单个对象
     * rowMapper:是个接口
     */
    @Override
    public Customer findCustomer(String id) {
        String sql = "select * from `t_customer` where cid = ?";
        Object[] obj = {id};
        return jt.queryForObject(sql, new RowMapper(){
            /*
             * rs:查询结果集
             * rowNum:表示当前结果集是第几行  0 表示第一行
             * 如果是单个对象  rowNum永远等于零
             * 下面这个方法表示循环遍历结果集   也就是不需要我们再去写while循环
             */
            public Customer mapRow(ResultSet rs, int rowNum)
                    throws SQLException {
                //手工解析结果集  封装Customer对象
                Customer c = new Customer();
                c.setId(rs.getString(1));
                c.setName(rs.getString(2));
                c.setGender(rs.getString(3));
                c.setBirthday(rs.getDate(4));
                c.setCellphone(rs.getString(5));
                c.setEmail(rs.getString(6));
                c.setDescription(rs.getString(7));
                return c;
            }
        }, obj);
    }

    @Override
    public List findAllCustomer() {
        String sql = "select * from `t_customer` ";

        return jt.query(sql, new RowMapper() {
            /*
             * rs:查询结果集
             * rowNum: 表示当前结果集是第几行, 0表示第一行
             * 如果是单个对象, rowNum永远等于零
             * 下面这个方法表示循环遍历结果集, 也就是不需要我们再去写while循环
             */
            @Override
            public Customer mapRow(ResultSet rs, int j) throws SQLException {
                //手工解析结果集  封装Customer对象
                Customer c = new Customer();

                c.setId(rs.getString(1));

                c.setName(rs.getString(2));
                c.setGender(rs.getString(3));
                c.setBirthday(rs.getDate(4));
                c.setCellphone(rs.getString(5));
                c.setEmail(rs.getString(6));
                c.setDescription(rs.getString(7));

                return c;
            }
        });
    }
}

测试主类:

        // 启动IOC容器
        ApplicationContext ac = new ClassPathXmlApplicationContext(
                new String[]{"com/wtu/spring/dao/annotation/spring3.0.xml"});

        UserDao userDao = (UserDao) ac.getBean("userDaoImpl");
        Customer c = userDao.findCustomer("no4");
        System.out.println(c);

注解总结:
Spring中的注解:
1.实例化对象的注解
@Component @Repository @Controller @Service
2.依赖注入
@Resource @Autowired
3.aop的注解
@After @Before @Around @After-returnning @After-throwing
@Aspect
@Pointcut
4.事务的注解
@Tranactional

完整代码见Github地址

https://github.com/menglanyingfei/SSMLearning/tree/master/spring_day03

你可能感兴趣的:(SSM,SSM框架系列学习总结)