1.复习
1. spring . aop开发
aop思想, 纵向重复, 横向抽取
|-filter 中
|-动态代理
|-interceptor 中 struts2框架中的拦截器
spring AOP : 封装了动态代理技术, 来体现aop
springaop实现: 可以对所有的对象代理
|-动态代理, 代理实现接口
|-cglib代理,对目标对象继承代理
springaop名词:
join point : 连接点, 所有可以植入通知的方法
point cut : 切入点,需要已经织入的通知的方法
advice : 需要增强的代码
weaving: 动词, 将通过应用的切点的过程
target : 目标对象
proxy : 代理对象
aspect : 切面,切入点,+ 通知
2.spring 中的springaop 的应用
1.导包
4+2
2 aop+aspect
2 aop联盟+weaving
2.准备目标对象
3.准备通知类
前置通知
后置通知 方法正常结束
环绕通知
异常拦截通知
后置通知 无论如何都执行
4.配置文件中配置,导入aop约束
1>目标对象
2>通知对象
3><aop:config>
<aop:ponint-cut id="切点名称" expression="execution(切点表达式)" />
<aop:aspect ref="通知对象名称" >
<aop:before method="" ponintcut-ref="" />
<aop:after-returning method="" ponintcut-ref="" />
<aop:around method="" ponintcut-ref="" />
<aop:after-throwing method="" ponintcut-ref="" />
<aop:after method="" ponintcut-ref="" />
</aop:aspect>
扩展:使用注解完成aop
1.导包
4+2
2 aop+aspect
2 aop联盟+weaving
2.准备目标对象
3.准备通知类
4.配置文件中配置,导入aop约束
1>目标对象
2>通知对象
3><aop:aspect-autoproxy> 开启注解aop
5.注解
@Aspect 指定当前类是通知类
@Before 前置通知方法
@after-returning 后置通知方法
@around 环绕通知方法
@after-throwing 异常拦截通知方法
@after 后通知方法
@PointCut 抽取切点表达式
2.spring整合jdbc (spring 中封装了jdbc对象, 通过这个对象可以操作数据库,这个对象叫做,JDBCTemplate, 和dbutils 中的queryrunner 几乎一模一样)
2.1 整合jdbc 模板
1. 导包
2.使用核心类,操作数据库
@Test
public void test() throws Exception {
// 0. 准备连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql:///hibernate");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("123456");
// 1.创建jdbc 模板对象
JdbcTemplate jt = new JdbcTemplate(dataSource);
// 书写sql
String sql = "insert into s_user values(3,'rose','4545')" ;
jt.update(sql);
}
2.2 演示 1.定义dao 接口
package com.zzq.dao;
import java.util.List;
import com.zzq.domain.User;
/**
* dao 定义对user 的操作
* @author ZZQ.Hacker
*
*/
public interface UserDao {
void add (User user);
void delete(Integer id ) ;
void update(User user);
List<User> findAll();
User getById(Integer id ) ;
Integer getTotalCount();
}
2.定义dao 实现类
package com.zzq.dao.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.zzq.dao.UserDao;
import com.zzq.domain.User;
@SuppressWarnings("all")
public class UserDaoimpl implements UserDao {
private static JdbcTemplate jt ;
static{
try{
// 0. 准备连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql:///hibernate");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("123456");
// 1.创建jdbc 模板对象
jt = new JdbcTemplate(dataSource);
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public void add(User user) {
String sql = "insert into s_user values(?,?,?); " ;
jt.update(sql, user.getId(),user.getName(),user.getPassword());
}
public void delete(Integer id) {
String sql = "delete from s_user where id = ? " ;
jt.update(sql,id);
}
public void update(User user) {
String sql = "update s_user set name=? password=? where id=? " ;
jt.update(sql,user.getName(),user.getPassword(),user.getId());
}
public List<User> findAll() {
String sql = "select * from s_user" ;
List<User> users= jt.query(sql, new RowMapper<User>(){
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User user = new User() ;
user.setId(rs.getInt("id"));
user.setName(rs.getString("username"));
user.setPassword(rs.getString("password"));
return user;
}
});
return users;
}
public User getById(Integer id) {
String sql = "select * from s_user where id = ? ";
User user = jt.queryForObject(sql,new RowMapper<User>(){
public User mapRow(ResultSet rs, int arg1) throws SQLException {
// 把resultset 中的内容取出,然后进行 封装, int 是索引
User u = new User() ;
u.setId(rs.getInt("id"));
u.setName(rs.getString("name"));
u.setPassword(rs.getString("password"));
return u ;
}
}, id );
return null ;
}
public Integer getTotalCount() {
String sql = "select count(*) from s_user";
return jt.queryForObject(sql, Integer.class);
}
}
4.测试
package com.zzq.jdbctempate;
import java.util.List;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.zzq.dao.UserDao;
import com.zzq.dao.impl.UserDaoimpl;
import com.zzq.domain.User;
/**
* 演示jdbc 模板
* @author ZZQ.Hacker
*
*/
public class Demo {
private UserDao u =new UserDaoimpl();
@Test
public void test() throws Exception {
// 0. 准备连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql:///hibernate");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("123456");
// 1.创建jdbc 模板对象
JdbcTemplate jt = new JdbcTemplate(dataSource);
// 书写sql
String sql = "select * from s_user" ;
List query = jt.query(sql,new BeanPropertyRowMapper(User.class));
System.out.println(query);
}
@Test
public void test_findAll(){
List<User> list = u.findAll();
System.out.println(list);
}
}
3.jdbc连接池,dao 配置到spring容器中
bug : 注意, 这里要理解, spring其实就是一个容器, 通过配置文件可以放入中, 配置文件可以是set 放入 , 和构造方法放入, 然后我们通过注解 @reSource 进行取出, 所以放进去的需要的时候就可以进行取出, 我今天就在这里犯了个错误 ,存入了jdbcTemplate 但是没有取出 ,然后我就直接想进行获取dao 然后进行查询 代码如下
1. daoimpl 层代码
package com.zzq.dao.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import com.zzq.dao.UserDao;
import com.zzq.domain.User;
public class UserDaoimpl extends JdbcDaoSupport implements UserDao {
@Resource(name="jdbcTemplate")
private JdbcTemplate jt;
public Integer getTotalCount() {
String sql = "select count(*) from s_user ";
Integer count = super.getJdbcTemplate().queryForObject(sql, Integer.class);
return count;
}
public List<User> findAll() {
String sql = "select * from s_user ";
List<User> list = jt.query(sql, new RowMapper<User>(){
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("username"));
u.setPassword(rs.getString("password"));
return u;
}});
return list;
}
} // 这里注意, 一定要从spring 中取出 ,对象 ,然后才能进行操作
配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" 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-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
<bean name="user" class="com.zzq.domain.User"></bean>
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="jdbc:mysql:///hibernate"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="user" value="root" ></property>
<property name="password" value="123456"></property>
</bean>
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean name="userDao" class="com.zzq.dao.impl.UserDaoimpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
测试如下 :
package com.zzq.jdbctempate;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.zzq.dao.UserDao;
import com.zzq.dao.impl.UserDaoimpl;
import com.zzq.domain.User;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo2 {
@Resource(name="userDao")
private UserDao us ;
@Test
public void test(){
System.out.println(us.findAll());
}
@Test
public void test2(){
System.out.println(us.getTotalCount());
}
}
2.3 Spring 整合jdbc 扩展, jdbcdaosupport 如果daoimpl 继承了 jdbcdaosupport , jdbcdaosupport 会自动读取配置文件中的
JdbcTemplate
对象, 然后我们直接调用父类的方法即可, 效果如下用super 关键字 调用父类的方法 :
本来我们需要把 ,dataSource 数据源放入,jdbcTempate 中, 然后把jdbctempate 注入到dao 中, 但是用了这个之后 , 关系变了, 直接把dataSource 传入jdbcTempate 然后通过继承关系, 直接就dao 用了jdbctemapte 模板对象 , 所以使得关系变得简单
2.4 读取properties 配置文件
由于, 由于程序的可拓展性, 所以用一个properties书写数据库的链接 , 在Spring 中 properties 书写时候 ,最好加一个前缀, 因为, 有的建容易和其他的冲突, 前缀随便加, 效果如下 :
jdbc.jdbcUrl=jdbc:mysql:///hibernate
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=123456
然后我们在applicationContext 引入properties 文件, 用context 标签, 需要引入context 约束的哦,然后用local host 属性, 填写地址 ,然后即可
3. springAop 事务管理
3.1 复习
1.事务特性, :acid
原子性 : 强调事务的不可分割
一致性: 事务执行前后数据的完整性一直
隔离性 : 一个事务的执行不受任何干扰
持久性: 事务一旦执行, 就永久保存进数据库
2. 并发问题
脏读,一个是事务读到了一个未提交的事务
不可重复读, 一个事务都到了一个已经提交的事务, 导致事务进行了两次
幻读, 一个事务读到了一个已经提交的insert 事务, 导致,多次查询不一致
3. 事务的隔离级别
未提交读 : 脏读, 不可重复度,虚读有可能发生
已提交读: 避免脏读, 但是不可重复读,和虚读都有可能发生
可重复读 : 避免脏读和不可重复读 ,但是虚读都有可能发生
串行化 : 避免以上所有的问题
mysql : 默认是可重复读
oracle : 默认是已提交
3.2 spring 封装了管理代码 (开启事务的代码, 提交事务的代码,回滚事务的代码)
因为不同的平台,操作的事务代码各不相同, spring 提供了一个接口
1.PlatformTransactionManager 接口
JDBCTransactionManager jdbc 平台 实现类
HibernateTransactionManager hibernate 平台 实现类
注意 : 在spring 中玩事务, 最核心的对象就是TransactionManager
2.spring 中的管理事务的属性介绍
事务的隔离级别
事务是否只读(如果为只读, 就不能操作数据库中的数据)
事务的传播行为
3.3 事务演示
银行转账案例 :
我们通过事务控制,然后让两个用户之间相互转账
注意 : bug 我们注入的时候 , 一定要name对着相应的配置文件才可以
package com.zzq.dao.impl;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import com.zzq.dao.AccountDao;
public class AccountDaoimpl extends JdbcDaoSupport implements AccountDao {
// 加钱
public void increaseMoney(Integer id, Double money) {
String sql = "update t_account set money =money+? where id=? " ;
this.getJdbcTemplate().update(sql, money,id);
}
//减钱
public void decreaseMoney(Integer id, Double money) {
String sql = "update t_account set money =money-? where id=? " ;
super.getJdbcTemplate().update(sql,money,id);
}
}
书写service 层 :
package com.zzq.service.impl;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import com.zzq.dao.AccountDao;
import com.zzq.service.AccountService;
public class AccountServiceimpl implements AccountService{
// 让dao层注入进来
private AccountDao acc ;
private TransactionTemplate transactionTemplate ;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void setAcc(AccountDao acc) {
this.acc = acc;
}
public void transfer(final Integer from, final Integer to, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
// 减少钱
acc.decreaseMoney(from,money);
// 加钱
acc.increaseMoney(to, money);
}
});
}
}
配置文件配置 :
首先我们创建transactionmanger 事务控制核心类 事务核心类需要依赖datasource 的链接对象,
然后创建事务模板对象
3.3.2 使用配置文件管理事务(aop) spring为我们准备了事务通知(环绕通知)
1. 首先我们要配置通知 我们可以通过*进行匹配性的代理 事务
2.植入通知与切点结合 形成切面
这里的execution 表达式, 中的*表示统配
注意 : 一定要注入事务和dao层, 不然抛异常 提供和set 方法 进行注入
3.3.3 注解进行控制事务
通过注解
配置文件中开启注解控制事务的代码 配置这个之后 就可以用注解配置事务
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
这个注解直接放在方法的头上即可, 但是这样每个方法都要加这个注解, 显得臃肿, 因此我们可以直接写在类上
如果下面的方法有不同, 就在每个单独的方法进行加这个注解
今天的课程笔记完结 !!! 明天激动人心的 spring 整合 struts2 hibernate 哈哈 然后Oracle