在这里先把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"
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
环绕通知默认情况下代理对象只会调用一次服务代码,连目标对象的业务方法都不会调用。
因此, 我们需要借助一个类, 去手动调用
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
首先是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("删除用户");
}
}
AOP各种注解总结:
SpringAOP的注解形式:
@Aspect
: 一般使用在切面的类名上面,作用是指定该类是一个切面
@PointCut
:配置在目标对象的方法上面, 表示该方法是一个切入点
@Around
@After
@Before
@After-returning
@After-throwing
配置在切面的方法上面, 表示何种通知方式.
Spring 数据访问, 因为Spring提供了对事务的支持!
所以, 我们首先来认识事务!
将一系列对数据库的操作进行捆绑,其中所有的操作要么全部执行成功, 要么全部执行不成功。
ACID特性
原子性 Atomicity
一致性 Consistency
隔离性 Isolation
持久性 Durability
mysql会将一条sql语句当成是一个完整的事务!
Mysql中对事务操作:
start transaction – 开启事务
commit – 提交事务
rollback – 回滚事务
对事务的管理在同一个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();
}
}
}
1.脏读 一个事务读取了另一个事务未提交的数据 绝对不允许存在
2.不可重复读 : 一个事务对某一条记录的两次读取结果不一致,原因是另一个事务在两次读取期间对该记录进行了修改,Oracle数据库中就有这种问题, 对应数据库update操作
3.虚读/幻读: 一个事务对某一张表的两次读取结果不一致,原因是另一个事务在两次读取期间对该表进行了insert 或者 delete操作 mysql中就有这种问题
针对数据库并发访问的问题, 出现了隔离级别的概念
1.serializable 串行化 数据库不支持并发访问, 隔离级别最高,效率最低 不推荐使用
2.repeatable read 可重复读, mysql默认隔离级别
3.Read Commited 读已提交的数据, Oracle的默认隔离级别
4.Read uncommited 读未提交的数据, 出现脏读, 效率是最高的 但是不推荐使用
事务一般作用在javaWeb的service层.
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();
}
Spring Dao模块提供了一个JDBC模板,那么通过这个模板操作数据库,有点类似于QueryRunner
.
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;
}
});
}
}
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
https://github.com/menglanyingfei/SSMLearning/tree/master/spring_day03