您的位置:首页 > 编程语言 > Java开发

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

2017-08-12 15:40 666 查看

一、AOP注解(注解方式)

在Spring02中讲述了xml方式的aop,现在讲解aop的注解形式。


导入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包一样)

导入约束

导入AOP的约束

在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>


在增强类中打上注解。

@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模板 入门 – 以向数据库插入数据为例子

导入jar包

额外导入 三个jar包

spring-jdbc-xxx.jar

spring-tx-xxx.jar (事务的包)

jdbc的驱动包

写代码

如何写这段代码:

只需要记住一个关键的类名: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

导入jar包

Spring-jdbc-XXX.jar

Spring-tx-xxx.jar

当然还有jdbc驱动包

导入约束

aop \ tx \bean 约束

配置事务

可以看出,事务的本质也是进行了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. 声明式 - 注解(重要 - 最常用的方式)

在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("保存成功");
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring aop 事务