AOP(面向切面编程)
特点:不通过修改源代码的方式添加新功能(这个详细可以去百度)
1.AOP(底层原理)
AOP底层使用动态代理:一般有两种:
一种是有接口(使用JDK动态代理),另一种是没有接口(使用CGLIB动态代理)
有接口的我们是通过:创建接口实现类代理对象,增强方法
没有接口的我们是通过:创建代理类子类的代理对象,增强方法
JDK动态代理
1.使用JDK动态代理,使用proxy类里面方法创建代理类对象(newProxyInstance),这个方法返回指定接口的代理类的实列 ,该方法将方法调用分派给指定的调用处理程序
newProxyInstance(classLoader loader,类<?> interfaces,InvocationHandler h)
这个方法有三个参数
第一个参数:类加载器
第二个参数:增强方法所在类,这个类实现的接口,支持多个接口
第三个参数:这个参数是一个对象而这个对象需要去实现一个InvocationHandler接口,
InvocationHandler接口里面有一个invoke()方法
invoke(Object proxy, Method method, Object[] args)方法有三个参数:
第一个是:代理对象
第二个是:当前方法
第三个是:当前参数
method.invoke( 对象,参数);执行方法
我们先来测试一下 用法:
准备工作:
1.创建一个dao包在包中写Userdao.java接口和UserdaoImpl.java去实现这个接口
2.在创建一个proxy包在包中写JDKproxy.java实习(newProxyInstance)通过这个方法我们来增强UserdaoImpl.java类
在Userdao.java接口中写两个方法add()和zhi()两个方法
package com.xiaoran.spring.dao;
public interface Userdao {
public int add(int a, int b);
public String zhi(String t);
}
在UserdaoImpl.java中写
package com.xiaoran.spring.dao;
public class UserdaoImpl implements Userdao {
public int add(int a, int b){
return a+b;
}
public String zhi(String a){
return a;
}
}
创建JDKproxy.java在类中写
package com.xiaoran.spring.proxy;
import com.xiaoran.spring.dao.Userdao;
import com.xiaoran.spring.dao.UserdaoImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKproxy {
public static void main(String args[]) {
//创建接口实现类代理对象
Class[] interfac = {Userdao.class};
UserdaoImpl userdao=new UserdaoImpl();
Userdao userdao1=(Userdao) Proxy.newProxyInstance(JDKproxy.class.getClassLoader(), interfac, new invocationHandler(userdao));
userdao1.add(1,2);
}
}
class invocationHandler implements InvocationHandler {
//把创建的是谁的代理对象,把谁传递过来
//有参构造
private Object obj;
public invocationHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法之前执行:" + method.getName() + "传递的参数:" + Arrays.toString(args));
Object res=method.invoke(obj,args);
System.out.println("方法之后执行");
return res;
}
}
最后执行的结果为:
springAOP中的 术语
- 连接点:类里面哪些方法可以被增强,这些方法称为连接点。
- 切入点:实际被真正增强的方法,称为切入点
- 通知:实际增强的逻辑部分我们就称为通知
- 切面:把通知应用到切入点的过程
ASPectJ
spring框架中一般都是基于ASPectJ实现AOP操作
ASPectJ实现AOP操作:
1.基于xml配置文件实现
2.基于注解方式实现(使用多一些)
准被工作我们需要引入AOP依赖:直接把这个 lib包添加进去
切入点表达式::
语法结构:execution([权限修饰符][返回值类型][类全路径]方法名称)
列子1:对com.xiaoran.spring.dao.BookDao 中的add增强
* 表示所有
execution(* com.xiaoran.spring.dao.BookDao.add(..))
Aop操作Aspect注解
1.创建一个类User.java
2,创建一个增强类Userproxy.java
(1)在增强类中创建方法,让不同的方法代表不同的通知类型
3.进行通知配置
(1)在spring.xml中开启注解扫描
(2)使用注解创建以上两个类
(3)在增强类上面添加注解@Aspect 这个注解的意思是:这个类生成一个你的代理对象
(4)在spring配置文件中开启生成代理对象
接下来我们就来实现一下:
1.我们新创建一个User.java在里面写一个add()方法,我们直接使用注解@component的方式创建对象
就不用在bean中写了
package com.xiaoran.spring.aspectAnno;
import org.springframework.stereotype.Component;
@Component
public class User{
public void add(){
System.out.println("add...。。方法执行");
}
}
2.创建一个Userproxy.java在这里面写我们增强的方法,
用一个注解@component//创建对象
用一个注解@Aspect//开启代理生成对像
在增强类里面,在作为通知方法上面添加通知类注解,使用切入点表达式配置
通知类注解有5种:
- @Before 前置通知
- @After 在方法执行之后通知
- @AfterThrowing 异常通知
- @Around 环绕通知
- @AfterReturning 方法返回结果之后通知
在引入注解里面的格式就是
@Before(value=“”)value中写的就是我们针对哪个类里面的哪个方法增强
package com.xiaoran.spring.aspectAnno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect//开启代理生成对象
public class Userproxy {
@Before(value = "execution(* com.xiaoran.spring.aspectAnno.User.add(..))")
public void before(){
System.out.println("前置通知。。。。。。");
}
}
3.我们在spring.xml中配置:
我们需要去引入context
打开扫描,在配置文件中开启生成代理对象
<?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 ">
<!--配置扫描-->
<context:component-scan base-package="com.xiaoran.spring"></context:component-scan>
<!--配置文件中开启生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
4.最后写一个测试类来查看一下结果
package com.xiaoran.spring.testdemo;
import com.xiaoran.spring.aspectAnno.User;
import com.xiaoran.spring.config.Configxml;
import com.xiaoran.spring.xmlbook.Book;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testproxy {
@Test
public void test1(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
User user =context.getBean("user",User.class);
user.add();
}
}
我们的得到的结果是
注意其他5种方法的执行过程都是一样的,只有一种注解用法有点不同(@Around)环绕注解
环绕注解我们在使用过程中:我的增强类方法中是需要引入一个(ProceedingJoinPoint)参数用它里面的方法(proceed)来调用我们被增强的方法
@Around(value = "execution(* com.xiaoran.spring.aspectAnno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前执行/......");
//被增强方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕之后执行");
}
其他的不需要改变我们来查看一下结果
我还是把所有的注解都实现一下把,大家可以看一下,在Userproxy.java中写
package com.xiaoran.spring.aspectAnno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect//开启代理生成对象
public class Userproxy {
@Before(value = "execution(* com.xiaoran.spring.aspectAnno.User.add(..))")
public void before(){
System.out.println("前置通知。。。。。。");
}
@After(value = "execution(* com.xiaoran.spring.aspectAnno.User.add(..))")
public void after(){
System.out.println("在方法执行之后执行。。。。。。");
}@AfterThrowing(value = "execution(* com.xiaoran.spring.aspectAnno.User.add(..))")
public void Theowing(){
System.out.println("异常通知。。。。。。");
}
@AfterReturning(value = "execution(* com.xiaoran.spring.aspectAnno.User.add(..))")
public void Runturn(){
System.out.println("方法返回结果后通知。。。。。。");
}
@Around(value = "execution(* com.xiaoran.spring.aspectAnno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前执行/......");
//被增强方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕之后执行");
}
}
注意了注意了,接下来就又是细节操作了
1.如果有两个类都对一个方法做增强,那么我们可以设置一下增强类的优先级
(1)在增强类上面添加注解@order(数字类型值)这里值越小优先级越高
AOP操作(AspectJ在spring.xml中配置通知)
1.创建两个类
2.spring中创建两个类对像book.java和Mybook.java
3.在spring中配置文件的切入点
1.创建book.java类在类中写一个add()方法
package com.xiaoran.spring.xmlbook;
public class Book {
public void add(){
System.out.println("这个是adddxxxxxx。。。。。。。。。。");
}
}
创建Mybook.java在类中写:我们的增强类(buy())
package com.xiaoran.spring.xmlbook;
public class Mybook {
public void buy(){
System.out.println("这是我们增强的方法");
}
}
2.在spring中怕配置:
(1)先用bean标签创建我们的两个对象
<bean id="book" class="com.xiaoran.spring.xmlbook.Book"></bean>
<bean id="mybook" class="com.xiaoran.spring.xmlbook.Mybook"></bean>
(2)配置aop增强
<!--配置aop增强-->
<aop:config>
<!--切入点id是自己设置,后写的是给哪个类,增强哪个方法-->
<aop:pointcut id="p" expression="execution(* com.xiaoran.spring.xmlbook.Book.add(..))"/>
<!--配置切面:这个就是配置我们去增强别人的类 -->
<aop:aspect ref="mybook![请添加图片描述](https://img-blog.csdnimg.cn/58b528df524e45d0bc20dca1f99ab06c.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP5YaJMQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
">
<!--增强作用在具体的方法上面:method:写的是我们的增强类中的方法名字(增强方法) pointcut-ref:这 个是引入我们的切入点-->
<aop:before method="buy" pointcut-ref="p"></aop:before>
</aop:aspect>
</aop:config>
3.写一个测试类:
@Test
public void test2(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring2.xml");
Book user =context.getBean("book",Book.class);
user.add();
}
之后的结果为:
纯注解开发
1.纯注解开法就是不需要spring.xml,我们就以上面为实列写修改一下来说明
创建一个Configxml.java来替代我们之前写的spring.xml
在这个类中写:@ComponentScan(basePackages = {“com.xiaoran.spring”}),这个就是我们的配置扫描
@EnableAspectJAutoProxy(proxyTargetClass = true)//开启Aspect成为代理对象
package com.xiaoran.spring.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
//配置扫描
@ComponentScan(basePackages = {"com.xiaoran.spring"})
//开启Aspect成为代理对象
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class Configxml {
}
在book.java中添加注解@Component
package com.xiaoran.spring.xmlbook;
import org.springframework.stereotype.Component;
@Component
public class Book {
public void add(){
System.out.println("这个是adddxxxxxx。。。。。。。。。。");
}
}
在Mybook.java中添加注解
package com.xiaoran.spring.xmlbook;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect//开启代理对象
public class Mybook {
@After(value = "execution(* com.xiaoran.spring.xmlbook.Book.add(..))")
public void buy(){
System.out.println("这是我们增强的方法");
}
}
测试类中其他地方不需要去改变,我们只需要去改变测试类中的代码把获取spring.xml的地方改为获取Configxml.class类
@Test
public void test3(){
ApplicationContext context=new AnnotationConfigApplicationContext(Configxml.class);
Book user =context.getBean("book",Book.class);
user.add();
}
最后的结果为:
JdbcTemplate
1什么jdbcTemplate:spring框架对jdbc进行封装,使用jdbcTemplate方便实现对数据库的操作
2.准备工作:
(1)引入依赖:mysql连接数据库的jar包
只需要这5个包但是你也可以全部引入,包去哪找这个问题很重要,传送门
2.在spring.xml中配置mysql数据库连接池,每个人的密码和名字不同,我这里使用的是我的test库
<!--配置数据库连接池-->
<bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="mysql123456"></property>
</bean>
3.在spring.xml中配置jdbcTemplate对象,注入DataSource,注意注意这里我们是用set注入大家可以看源码
<!--配置jdbcTemplate对象,注入DataSource-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--在这里面我们需要用set注入我们的数据库连接池-->
<property name="dataSource" ref="datasource"></property>
</bean>
4.创建service类和dao类
(1)在配置文件中还要记得打开扫描
<!--配置扫描 -->
<context:component-scan base-package="com.xiaoran.spring"></context:component-scan>
(2)在service类中注入dao
(3)在dao中注入 JdbcTemplate
5.在mysql中创建一个非常简单的 表test1
在mysql中写
create table test1(
id int,
name char(12),
age int
)
我们的准备工作就完成了
用JdbcTemplate对数据库进行添加操作
我们在创建一个entity包,创建对应我们数据库中的实体
添加一个get和set 和tostring方法
package com.xiaoran.spring.entity;
public class Book {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.我们在service类中创建一个类BookService.java
我们在类中注入dao类
通过Bookservice类去调用我们的添加方法()
@Component
public class BookService {
@Autowired//注入dao类
private BookDao bookDao;
//添加的方法
public void add(Book book){
bookDao.add(book);
}
}
3.在dao中创建一个BookDao.java接口和BookDaoImple.java来实现接口
BookDao.java
public interface BookDao {
public void add(Book book);
}
在BookDaoImpl.java中写:
在这里就要重点说一下了注意了哟,
我们在这里引入JdbcTemplate 我们使用它里面的一个方法 update(参数1,参数2[ ])
参数1:是我们写的sql语句
参数2:是我们sql语句中问号表示的值,因为有 时我们的问号有多个,所以这是一个数组类
@Component
public class BookdaoImpl implements BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Book book){
String sql="insert into test1 values (?,?,?)";
Object[] args={book.getId(),book.getName(),book.getAge()};
int update=jdbcTemplate.update(sql,args);
System.out.println(update);//这里我们输出一下影响的行数
}
}
4.最后我们在写一个测试类:这里我们添加的是一个对像所以我们需要创建一个book对象用set放值,后面我们在BookDaoImpl.java中用get方法取出值
@Test
public void Test(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
Book book=new Book();
book.setId(1);
book.setName("小冉好帅");
book.setAge(20);
bookService.add(book);
}
最后我们需要在mysql中查看一下结果
select * from test1
我们简简单单总结一下主要就时我们要记住JdbcTemplate中的这个update()方法的使用;
用JdbcTemplate对数据库进行修改操作
这个和上面没有什么区别,主要区别就是sql语句不同
在BookService中添加一个方法
//修改的方法
public void updatebook(Book book){
bookDao.updatebook(book);
}
在BookDao.java中添加一个方法
public void updatebook(Book book);
在BookdaoImpl.java中添加一个实现方法
@Override
public void updatebook(Book book){
String sql="update test1 set name=?,age=? where id=?";
Object[] args={book.getName(),book.getAge(),book.getId()};
int update=jdbcTemplate.update(sql,args);
System.out.println(update);
}
最后我们写一个测试类:
@Test
public void test2(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
Book book=new Book();
book.setName("小芳");
book.setAge(20);
book.setId(1);
bookService.updatebook(book);
}
结果显示:
用JdbcTemplate对数据库进行删除操作
这个和上面没有什么区别,主要区别就是sql语句不同,还有就是我们删除是按照id删除
在BookService中添加一个方法
//删除的方法
public void deletebook(int i){
bookDao.deletebook(i);
}
在BookDao.java中添加一个方法
public void deletebook(int i);
在BookdaoImpl.java中添加一个实现方法
@Override
public void deletebook(int i){
String sql="delete from test1 where id=?";
int update=jdbcTemplate.update(sql,i);
System.out.println(update);
}
最后我们写一个测试类:
@Test
public void test3(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
int i=1;
bookService.deletebook(i);
}
结果显示:最后全部没有了
查询返回某个值
我们这里的列子是去查看数据库中有几个值count
在BookService中添加一个方法
//返回查询某个对象
public Book selectbook(int i){
Book book=bookDao.seletbook(i);
return book;
}
在BookDao.java中添加一个方法
public int selectint();
在BookdaoImpl.java中添加一个实现方法:在这里面我们要实现JdbcTemplate里面的
queryForObject(第一个参数,第二参数)方法,返回某个值
第一个参数是:sql语句
第二个参数是:class< T > requiredType 返回类型的class,返回的是什么类型就写什么类型
@Override
public int selectint(){
String sql="select count(*) from test1";
Integer integer=jdbcTemplate.queryForObject(sql,Integer.class);
return integer;
}
最后我们写一个测试类:
@Test
public void test3(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
int i=1;
bookService.deletebook(i);
}
结果显示:
查询返回对象用JdbcTemplate
在BookService中添加一个方法
//返回查询某个对象
public Book selectbook(int i){
Book book=bookDao.seletbook(i);
return book;
}
在BookDao.java中添加一个方法
public Book seletbook(int i);
在BookdaoImpl.java中添加一个实现方法:在这里面我们要实现JdbcTemplate里面的
queryForObject(第一个参数,第二参数第三个参数)方法,查询返回对象
第一个参数是:sql语句
第二个参数是:RowMapper接口,返回不同类型,使用这个接口里面的实现类完成数据
new BeanPropertyRowMapper<这里面写的是我们返回对象的名字>(返回对象.class)
第三个参数是:问号中的值
@Override
public Book seletbook(int i){
String sql="select * from test1 where id=?";
Book book=jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),i);
return book;
}
最后我们写一个测试类:
@Test
public void test5(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
int id=1;
Book book=bookService.selectbook(id);
System.out.println(book);
}
结果显示:
查询返回列表
在BookService中添加一个方法
//查询返回列表
public List<Book> select(){
List<Book> books=bookDao.select();
return books;
}
在BookDao.java中添加一个方法
public List<Book> select();
在BookdaoImpl.java中添加一个实现方法:在这里面我们要实现JdbcTemplate里面的
query(第一个参数,第二个参数),查询返回列表
第一个参数是:sql语句
第二个参数是:RowMapper接口,返回不同类型,使用这个接口里面的实现类完成数据
new BeanPropertyRowMapper<这里面写的是我们返回对象的名字>(返回对象.class)
@Override
public List<Book> select(){
String sql="select * from test1";
List<Book> list=jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));
return list;
}
最后我们写一个测试类:
@Test
public void test6(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
List<Book> list=bookService.select();
System.out.println(list);
}
结果显示:
JdbcTemplate操作数据库实现批量操作 添加
在BookService中添加一个方法
//实现对返回列表的批量处理
public void addall(List<Object[]> bat){
bookDao.addall(bat);
}
在BookDao.java中添加一个方法
public void addall(List<Object[]> bat);
在BookdaoImpl.java中添加一个实现方法:在这里面我们要实现JdbcTemplate里面的
batchUpdate(第一个参数,第二个参数),查询返回列表
第一个参数是:sql语句
第二个参数是:List<Object[]> batchArgs 这是一个集合放的是我们?的值,这里面可以放很多组
@Override
public void addall(List<Object[]> bat){
String sql="insert into test1 values(?,?,?)";
//调用batchupdate(sql,这是一个集合放的是我们?的值,这里面可以放很多组)
int[] ints=jdbcTemplate.batchUpdate(sql,bat);
System.out.println(Arrays.toString(ints));
}
最后我们写一个测试类:
@Test
public void test7(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
//创建一个 列表 用来存放我们的插入数据
List<Object[]> list= new ArrayList<>();
Object[] o1={3,"java",18};
Object[] o2={4,"mysql",18};
Object[] o3={5,"c++",20};
list.add(o1);
list.add(o2);
list.add(o3);
//调用批量处理
bookService.addall(list);
}
批量修改和删除和上面差不多
------------------------------------------------------------------------------------------
接下来我们就把全部补齐
在BookService中添加一个方法
package com.xiaoran.spring.service;
import com.xiaoran.spring.dao.BookDao;
import com.xiaoran.spring.entity.Book;
import org.aspectj.lang.annotation.After;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
//调用方法
@Component
public class BookService {
@Autowired//注入dao类
private BookDao bookDao;
//添加的方法
public void add(Book book){
bookDao.add(book);
}
//修改的方法
public void updatebook(Book book){
bookDao.updatebook(book);
}
//删除的方法
public void deletebook(int i){
bookDao.deletebook(i);
}
//查询返回结果
public int selectint(){
int count=bookDao.selectint();
return count;
}
//返回查询某个对象
public Book selectbook(int i){
Book book=bookDao.seletbook(i);
return book;
}
//查询返回列表
public List<Book> select(){
List<Book> books=bookDao.select();
return books;
}
//实现对返回列表的批量处理
public void addall(List<Object[]> bat){
bookDao.addall(bat);
}
//实现对列表的批量修改
public void updateall(List<Object[]> bat){
bookDao.updateall(bat);
}
//实现对数据库的批量删除
public void deleteall(List<Object[]> bat){
bookDao.deleteall(bat);
}
}
在BookDao.java中添加一个方法
package com.xiaoran.spring.dao;
import com.xiaoran.spring.entity.Book;
import java.util.List;
public interface BookDao {
public void add(Book book);
public void deletebook(int i);
public void updatebook(Book book);
public int selectint();
public Book seletbook(int i);
public List<Book> select();
public void addall(List<Object[]> bat);
public void updateall(List<Object[]>bat);
public void deleteall(List<Object[]> list);
}
在BookdaoImpl.java中:
package com.xiaoran.spring.dao;
import com.xiaoran.spring.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
//这里面写的对数据库的操作
@Component
public class BookdaoImpl implements BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Book book){
String sql="insert into test1 values (?,?,?)";
Object[] args={book.getId(),book.getName(),book.getAge()};
int update=jdbcTemplate.update(sql,args);
System.out.println(update);
}
@Override
public void updatebook(Book book){
String sql="update test1 set name=?,age=? where id=?";
Object[] args={book.getName(),book.getAge(),book.getId()};
int update=jdbcTemplate.update(sql,args);
System.out.println(update);
}
@Override
public void deletebook(int i){
String sql="delete from test1 where id=?";
int update=jdbcTemplate.update(sql,i);
System.out.println(update);
}
@Override
public int selectint(){
String sql="select count(*) from test1";
Integer integer=jdbcTemplate.queryForObject(sql,Integer.class);
return integer;
}
@Override
public Book seletbook(int i){
String sql="select * from test1 where id=?";
Book book=jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),i);
return book;
}
@Override
public List<Book> select(){
String sql="select * from test1";
List<Book> list=jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));
return list;
}
@Override
public void addall(List<Object[]> bat){
String sql="insert into test1 values(?,?,?)";
//调用batchupdate(sql,这是一个集合放的是我们?的值,这里面可以放很多组)
int[] ints=jdbcTemplate.batchUpdate(sql,bat);
System.out.println(Arrays.toString(ints));
}
@Override
public void updateall(List<Object[]> list){
String sql="update test1 set name=?,age=? where id=?";
int[] i= jdbcTemplate.batchUpdate(sql,list);
System.out.println(Arrays.toString(i));
}
@Override
public void deleteall(List<Object[]> list){
String sql="delete from test1 where id=?";
int[] i =jdbcTemplate.batchUpdate(sql,list);
System.out.println(Arrays.toString(i));
}
}
最后我们写一个测试类:
package com.xiaoran.spring.testdemo;
import com.xiaoran.spring.entity.Book;
import com.xiaoran.spring.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.List;
public class test {
@Test
public void Test(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
Book book=new Book();
book.setId(1);
book.setName("小冉好帅");
book.setAge(20);
bookService.add(book);
}
@Test
public void test2(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
Book book=new Book();
book.setName("小芳");
book.setAge(20);
book.setId(1);
bookService.updatebook(book);
}
@Test
public void test3(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
int i=1;
bookService.deletebook(i);
}
@Test
public void test4(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
int i =bookService.selectint();
System.out.println(i);
}
@Test
public void test5(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
int id=1;
Book book=bookService.selectbook(id);
System.out.println(book);
}
@Test
public void test6(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
List<Book> list=bookService.select();
System.out.println(list);
}
@Test
public void test7(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
//创建一个 列表 用来存放我们的插入数据
List<Object[]> list= new ArrayList<>();
Object[] o1={3,"java",18};
Object[] o2={4,"mysql",18};
Object[] o3={5,"c++",20};
list.add(o1);
list.add(o2);
list.add(o3);
//调用批量处理
bookService.addall(list);
}
@Test
public void test8(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
//创建一个 列表 用来存放我们的插入数据
List<Object[]> list= new ArrayList<>();
Object[] o1={"java 小冉帅",18,3};
Object[] o2={"mysql 小冉帅",18,4};
Object[] o3={"c++ 小冉帅",20,5};
list.add(o1);
list.add(o2);
list.add(o3);
//调用批量处理
bookService.updateall(list);
}
@Test
public void test9(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService=context.getBean("bookService",BookService.class);
//创建一个 列表 用来存放我们的插入数据
List<Object[]> list= new ArrayList<>();
Object[] o1={3};
Object[] o2={4};
Object[] o3={5};
list.add(o1);
list.add(o2);
list.add(o3);
//调用批量处理
bookService.deleteall(list);
}
}
我们对数据库的操作就结束了,多练习其实不难
事务
1.什么是事务,事务是数据库操作最基本单元,逻辑上的一组操作,要么都成功,如果有一个失败那么所有操作都会失败。
2.事务的作用很广泛如:我们的银行转账,必须是一个人扣钱了一个人才可以收到钱,如果转载过程中断电了那么就会转账失败。
3.我们创建一个简单的环境来实现:转帐环境搭建
(1)创建一个service类和dao类
(2)在dao类中写两个方法,一个是addmoney方法增加钱,一个是reduceMoney方法少钱的
(3)在service类中写:创建转钱的方法(1)调用dao中的两个方法
(2)创建一个数据库我们在数据库中写一个表用来记录转帐
mysql代码:
create table account(
id int,
name char(12),
money int
)
我们在创建的表中添加两个人小冉和小芳用来模拟他们两的交易,假设他们一开始钱都是1000
insert into account values(1,'小冉',1000)
insert into account values(2,'小芳',1000)
1.在dao中创建一个Userdao.java接口,在接口中写两个方法
package com.xiaoran.spring.dao;
public interface Userdao {
public void addmoney();//多钱
public void reduceMoney();//少钱
}
在dao中创建一个实现上面接口的方法:
在这个方法中实现接口中的方法我们实现 " 加钱" 或者 “少钱” 的方法就是直接修改数据库中我们余额
package com.xiaoran.spring.dao;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserdaoImpl implements Userdao{
@Autowired
private JdbcTemplate jdbcTemplate;
//多钱
public void addmoney(){
String sql="update account set money=money+? where name=? ";
jdbcTemplate.update(sql,100,"小冉");
}
//少钱
public void reduceMoney(){
String sql="update account set money=money-? where name=? ";
jdbcTemplate.update(sql,100,"小芳");
}
}
3.我们创建一个UserService.java类在类中写:
package com.xiaoran.spring.service;
import com.xiaoran.spring.dao.Userdao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class Userservice {
//注入dao
@Autowired
private Userdao userdao;
//转载方法
public void accountmoney(){
//少钱
userdao.reduceMoney();
//多钱
userdao.addmoney();
}
}
4.我们需要在spring.xml中配置:配置扫描,配置数据库连接池,配置配置jdbcTemplate对象,注入DataSource
<?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:tx="http://www.springframework.org/schema/tx"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置扫描 -->
<context:component-scan base-package="com.xiaoran.spring"></context:component-scan>
<!--配置数据库连接池-->
<bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="mysql123456"></property>
</bean>
<!--配置jdbcTemplate对象,注入DataSource-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--在这里面我们需要用set注入我们的数据库连接池-->
<property name="dataSource" ref="datasource"></property>
</bean>
</beans>
最后我们写一个测试类:
@Test
public void test(){
ApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");
Userservice userservice=context.getBean("userservice",Userservice.class);
userservice.accountmoney();
}
执行之后我们查看数据库中的结果:
在mysql中写
select * from account;
结果显示:
事实证明我们的方法是有效的;但是这是我们所说的理想情况,在实际的过程中会有很多未知的变化,
接下来我们举个列子:
我们在UserService.java中添加一个异常,模拟我们在实际过程中出现了异常:
package com.xiaoran.spring.service;
import com.xiaoran.spring.dao.Userdao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class Userservice {
//注入dao
@Autowired
private Userdao userdao;
//转载方法
public void accountmoney(){
//少钱
userdao.reduceMoney();
//模拟异常
int i=10/0;
//多钱
userdao.addmoney();
}
}
接下来我们在执行就会发现,发现我们的小芳钱少了,而小冉的钱也没有增加,钱去哪了呢???
我们用之前的测试方法执行一下,结果显示为
所以我们就必须得引入事务啦
引入事务
1.在spring中进行事务管理操作
(2)有两种方法:编程式事务管理(了解)和声明式事务管理(使用多)
声明式事务管理:可以分为注解实现,和xml配置实现
2.在spring中进行声明事务管理(底层使用AOP原理)
事务操作(注解声明式事务管理)
1.我们在UserService.java上面添加一个注解:@Transactional 开启事务
2.我们需要在spring.xml中配置事务管理器:DataSourceTransactionManager,这里面我们需要用set注入我们的数据库连接池
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="datasource"></property>
</bean>
2.开启事务注解,前提我们需要在顶部引入tx和aop
<!--开启事务注解-->
<!--transaction-manager="transactionManager" 指定我们的事务管理器-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3.接下来我们在重新测试:
我们先把mysql中的数据还原一下
update account set money=1000 where name='小芳'
update account set money=1000 where name='小冉'
最后用以前的测试方法测试一下
@Test
public void test(){
ApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");
Userservice userservice=context.getBean("userservice",Userservice.class);
userservice.accountmoney();
}
在数据库中查看发现:
select * from account
测试结果为:
我们在添加了事务之后,只要有一个错误就不会提交事务
我们来看一下这个注解的用法吧:
@Transactional注解里面可以写6个值分别是
- Propagation :事务传播行,多事物直接或间接调用,这个过程中事务时如何管理的
propagation.REQUIRED:如果有事务在运行,当前方法就在这个事务中运行,否则就在启动一个新事物,并在自己的事务中运行;(默认是这个)
propagation.REQUIRED_NEW:当前的方法必须启动新事物并在它自己的事务内运行,如果有事务在运行应该将它先挂起 - Ioslation :事务隔离,多事物之间操作如果不设置隔离性,就会产生很多问题如:脏读,重复读,虚度
我们可以通过设置事务的隔离级别来解决问题
默认是:Ioslation.REDATABLEREAD(可重复读) - tiemout :超时间,默认是-1没有时间限制,超过我们设置的时间就会提交,不提交就会回滚
- readonly :是否只读,默认为false,可以查询可以添加修改删除操作,如果把值设置为True之后只能进行查询
- rollbackFor:回滚,设置出现哪些异常进行事务回滚
- norollbackFor:不回滚,设置出现哪些异常不进行事务回滚
事务操作(基于注解实现)
1.在xml中配置
(1)配置事务管理器
(2)配置事务通知
(3)配置切入点和切面
我们在spring.xml中配置:
配置事务管理器
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="datasource"></property>
</bean>
配置事务通知
<tx:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--
name=""这里写的是:指定哪种方法上面添加事务
propagation="" 这里面写的是:指定事务
-->
<tx:method name="accountmoney" propagation="REQUIRED"></tx:method>
</tx:attributes>
</tx:advice>
配置切面和切面
<!--配置切入点和 切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.xiaoran.spring.service.Userservice.accountmoney(..))"></aop:pointcut>
<!--配置切面advice-ref="txadvice" 这里面写的是把我们的通知配置进来
pointcut-ref="pt"引入切入点
-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
之后我们去掉在UserService.java中的注解@Transactional,执行的结果还是和之前的是一样的
完全纯注解开发
1.创建一个config包在包中创建一个Txcongifg.java类
(1)在类中添加注解@Configuration//配置类
@ComponentScan(basePackages = “com.xiaoran.spring”)//开启扫描
@EnableTransactionManagement//开启事务注解
package com.xiaoran.spring.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration//配置类
@ComponentScan(basePackages = "com.xiaoran.spring")//开启扫描
@EnableTransactionManagement//开启事务注解
public class Txcongifg {
//配置数据库连接池
@Bean
public DruidDataSource getdruidDataSource(){
DruidDataSource dataSource=new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("mysql123456");
return dataSource;
}
//配置jdbcTemplate对象,注入datasource
@Bean
public JdbcTemplate jdbctemplat(DataSource dataSource){
JdbcTemplate jdbcTemplate=new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//-配置事务管理器
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
之后我们写一个测试类:
package com.xiaoran.spring.Test;
import com.xiaoran.spring.config.Txcongifg;
import com.xiaoran.spring.service.Userservice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Testdemo2 {
@Test
public void test2(){
ApplicationContext context =new AnnotationConfigApplicationContext(Txcongifg.class);
Userservice userservice=context.getBean("userservice",Userservice.class);
userservice.accountmoney();
}
}
执行的结果和之前的还是一样的,大家可以去多练习一下