Spring两大核心之一:AOP(面向切面编程)含设计模式讲解,通知类型切点;附有案例,实现spring事务管理

模拟转账业务

pom.xml

<dependencies><!--spring--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.29</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><!--dbutil--><dependency><groupId>commons-dbutils</groupId><artifactId>commons-dbutils</artifactId><version>1.4</version></dependency><!--数据源c3p0--><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency><!--junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!--spring测试环境--><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.29</version></dependency>
</dependencies>

Bean:Account

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account implements Serializable {private int aid;private String aname;private int amoney;public Account(String aname, int amoney) {this.aname = aname;this.amoney = amoney;}}

Dao层:

接口

public interface IAccountDao {public void save(Account account);public void update(Account account);public Account findByName(String name);public List<Account> findAll();
}

实现类:

public class AccountDaoImp implements IAccountDao {QueryRunner queryRunner;public void setQueryRunner(QueryRunner queryRunner) {this.queryRunner = queryRunner;}ConnectionUtil connectionUtil;public void setConnectionUtil(ConnectionUtil connectionUtil) {this.connectionUtil = connectionUtil;}@Overridepublic void save(Account account) {try {queryRunner.update(connectionUtil.createConn(),"insert into acount(aname,amoney) values (?,?)", account.getAname(), account.getAmoney());} catch (SQLException throwables) {throwables.printStackTrace();}}@Overridepublic void update(Account account) {try {queryRunner.update(connectionUtil.createConn(),"update acount set aname=?,amoney=? where aid=?", account.getAname(), account.getAmoney(), account.getAid());} catch (SQLException throwables) {throwables.printStackTrace();}}@Overridepublic Account findByName(String name) {try {Account query = queryRunner.query("select * from acount where aname=?", new BeanHandler<Account>(Account.class), name);return query;} catch (SQLException throwables) {throwables.printStackTrace();}return null;}@Overridepublic List<Account> findAll() {try {List<Account> all = queryRunner.query("select * from acount", new BeanListHandler<Account>(Account.class));return all;} catch (SQLException throwables) {throwables.printStackTrace();}return null;}
}

Service层:

接口:

public interface IAccountService {public void save(Account account);public void update(Account account);public Account findByName(String name);public List<Account> findAll();public void transfer(String sourceName,String targetName,int money);
}

实现类:

public class AccountServiceImp implements IAccountService {IAccountDao dao;public void setDao(IAccountDao dao) {this.dao = dao;}TransactionUtil transactionUtil;public AccountServiceImp(TransactionUtil transactionUtil) {this.transactionUtil = transactionUtil;}@Overridepublic void save(Account account) {dao.save(account);}@Overridepublic void update(Account account) {dao.update(account);}@Overridepublic Account findByName(String name) {Account a = dao.findByName(name);return a;}@Overridepublic List<Account> findAll() {List<Account> all = dao.findAll();return all;}// 转账业务@Overridepublic void transfer(String sourceName, String targetName, int money) {try {transactionUtil.openTran();// 查询俩个人的账户状态Account sourceAccount = dao.findByName(sourceName);Account targetAccount = dao.findByName(targetName);// 转账sourceAccount.setAmoney(sourceAccount.getAmoney()-money);targetAccount.setAmoney(targetAccount.getAmoney()+money);// 修改数据dao.update(sourceAccount);int a = 10/0;dao.update(targetAccount);transactionUtil.commitTran();} catch (Exception e) {e.printStackTrace();transactionUtil.rollbackTran();}finally {transactionUtil.closeTran();}}
}

连接工具类ConnectionUtil:

public class ConnectionUtil {// 装配数据源DataSource dataSource;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();Connection connection =null;// 获取连接public Connection createConn(){try {connection = threadLocal.get();if(connection ==null){connection = dataSource.getConnection();threadLocal.set(connection);}return this.connection;} catch (SQLException throwables) {throwables.printStackTrace();}return connection;}// 关闭连接public void closeConn(){threadLocal.remove();}
}

事务管理工具类TransactionUtil:

public class TransactionUtil {// 装配连接ConnectionUtil connectionUtil;public void setConnectionUtil(ConnectionUtil connectionUtil) {this.connectionUtil = connectionUtil;}// 开启事务public void openTran(){try {connectionUtil.createConn().setAutoCommit(false);} catch (SQLException throwables) {throwables.printStackTrace();}}// 提交事务public void commitTran(){try {connectionUtil.createConn().commit();} catch (SQLException throwables) {throwables.printStackTrace();}}// 回滚事务public void rollbackTran(){try {connectionUtil.createConn().rollback();} catch (SQLException throwables) {throwables.printStackTrace();}}// 关闭事务public void closeTran(){try {connectionUtil.createConn().close();} catch (SQLException throwables) {throwables.printStackTrace();}}
}

Controller类:

接口:

public interface IAccountController {public void save(Account account);public void update(Account account);public Account findByName(String name);public List<Account> findAll();public void transfer(String sourceName,String targetName,int money);
}

实现类:

public class AccountControllerImp implements IAccountController {IAccountService service;public void setService(IAccountService service) {this.service = service;}@Overridepublic void save(Account account) {service.save(account);}@Overridepublic void update(Account account) {service.update(account);}@Overridepublic Account findByName(String name) {Account account = service.findByName(name);return account;}@Overridepublic List<Account> findAll() {List<Account> all = service.findAll();return all;}@Overridepublic void transfer(String sourceName, String targetName, int money) {service.transfer(sourceName,targetName,money);}
}

Spring主配置文件applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--注入数据源--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?serverTimezone=GMT"></property><property name="user" value="root"></property><property name="password" value="123456"></property></bean><!--注入连接工具类--><bean id="connectionUtil" class="com.dong.util.ConnectionUtil"><property name="dataSource" ref="dataSource"></property></bean><!--注入事务工具类--><bean id="transactionUtil" class="com.dong.util.TransactionUtil"><property name="connectionUtil" ref="connectionUtil"></property></bean><!--注入queryRunner--><bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner"><constructor-arg name="ds" ref="dataSource"></constructor-arg></bean><!--注入dao--><bean id="accountDaoImp" class="com.dong.dao.AccountDaoImp"><property name="queryRunner" ref="queryRunner"></property><property name="connectionUtil" ref="connectionUtil"></property></bean><!--注入service--><bean id="accountServiceImp" class="com.dong.service.AccountServiceImp"><property name="dao" ref="accountDaoImp"></property><constructor-arg name="transactionUtil" ref="transactionUtil"></constructor-arg></bean><!--注入controller--><bean id="accountControllerImp" class="com.dong.controller.AccountControllerImp"><property name="service" ref="accountServiceImp"></property></bean>
</beans>

模拟转账业务中,如果直接使用spring的事务管理的话,如果业务逻辑中产生异常,eg在修改两个人的金额之间出现异常,第一个人的金额发生改变,并提交了数据,因为产生异常第二个人的数据没有修改,造成数据不一致的问题,所以就需要想办法让一个业务共用一个连接,所以自定义了连接管理类和事务管理工具类,实现业务共用一个连接对象,业务层公用的连接一起提交或回滚

Java的六大设计原则

设计原则是为了更好的设计软件的高层指导方针,它不提供具体的实现方式也不会绑定任何一种编程语言,最常用的原则是SOLID(SRP, OCP, LSP, ISP, DIP)原则

  • 开闭原则(OCP) - The Open-Closed Principle
  • 单一职责原则(SRP) - Single Responsibility Principle
  • 里氏替换原则(LSP) - Liskov Substitution Principle
  • 依赖倒置原则(DIP) - Dependency Inversion Principle
  • 接口隔离原则(ISP) - Interface Segregation Principle
  • 迪米特法则(DP) - Demeter Principle

设计模式

设计模式对关于面向对象问题的具体解决方案;比如说,如果你想创建一个类而且它在任何时刻只会有一个对象,那么你就应该使用单例类模式

设计模式是经过大量检测的安全的做法

单例模式

单例模式性能好,但是安全性差

  • 饿汉模式:不管用不用,先创建一个对象,用的时候直接给
  • 懒汉模式:用的时候在创建对象,只创建一次,第二次用直接给不在创建
  1. 饿汉模式演示

    public class Student {/*饿汉模式*/private static Student stu=new Student();private Student() {}public static synchronized Student getInstance(){return stu;}
    }
    
  2. 懒汉模式演示

    public class Student {/*懒汉模式*/private static Student stu=null;private Student() {}public static synchronized Student getInstance(){if(stu == null){stu = new Student();}return stu;}
    }
    

工厂模式

演示:

INoodels接口

public interface INoodels {public void NoodelsType();
}

INoodels接口实现类:

  1. YouPoNoodle

    public class YouPoNoodels implements INoodels {@Overridepublic void NoodelsType() {System.out.println("油泼面");}
    }
    
  2. ReGanNoodel

    public class ReGanNoodls  implements INoodels{@Overridepublic void NoodelsType() {System.out.println("武汉热干面");}
    }
    
  3. LanZhouNoodel

    public class LanZhouNoodels implements INoodels {@Overridepublic void NoodelsType() {System.out.println("兰州牛肉面");}
    }
    

工厂NoodleFactory

public class NoodelFactory {public  static final int YOUPO_NOODEL=1;public  static final int REGAN_NOODEL=2;public  static final int LANZHOU_NOODEL=3;public static INoodels createNoodel(int type){if(type ==1){return new YouPoNoodels();}else if(type ==2){return new ReGanNoodls();}else if(type ==3){return new LanZhouNoodels();}return null;}
}

Test01

public class Test01 {public static void main(String[] args) {NoodelFactory.createNoodel(NoodelFactory.LANZHOU_NOODEL).NoodelsType();NoodelFactory.createNoodel(3).NoodelsType();}
}

工厂模式是由工厂帮我们创建对象

模板模式

模板模式==spring框内

* JdbcTemplate

* JpaTemplate

模板模式首先要有一个抽象类,这个抽象类公开定义了执行它的方法的方式/模板。

它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式

“比如,在造房子一样,地基,铺线,房子户型都是一样的,由开发商决定,但是在交房之后,室内的装修风格和场景布置却是由业主决定,在这个场景中,开发商其实就是一个抽象类,地基,铺线,房子户型都是可以复用的,但是装修却是不可复用的,必须由业主决定,此时的每一个业主的房子就是一个实现的子类”

Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到模板模式。一般情况下,我们都是使用继承的方式来实现模板模式,但是Spring并没有使用这种方式,而是使用Callback模式与模板方法配合,既达到了代码复用的效果,同时增加了灵活性

所谓模板板式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤

实现演示:

FatherClass:

public abstract class FatherClass {public final void life(){study();work();love();}public void study(){System.out.println("学C++");}public void work(){System.out.println("干嵌入式");}public abstract void love();
}

SonClass

public class SonClass extends FatherClass {@Overridepublic void study() {System.out.println("学java");}@Overridepublic void work() {System.out.println("干java开发");}@Overridepublic void love() {System.out.println("美女大妹");}
}

Test:

public class Test01 {public static void main(String[] args) {FatherClass fatherClass = new SonClass();fatherClass.人生();}
}

FatherClass类里面定义人生()方法被final修饰不能重写,规定了先学习,再工作,最后恋爱,体现了模板模式

代理模式

什么是代理模式?

​ 代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介公司来买车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。

为什么要用代理模式?

  • 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

  • 开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则

有哪几种代理模式?

有多种不同的方式来实现代理。如果按照代理创建的时期来进行分类的话可以分为两种:

静态代理:

​ 静态代理是由程序员创建或特定工具自动生成源代码,在对其编译在程序员运行之前,代理类.class文件就已经被创建了

动态代理:

​ 动态代理是在程序运行时通过反射机制动态创建的

  1. 基于接口的动态代理(jdk自带)
  2. 基于子类的动态代理(第三方)

静态代理

演示:假如西门庆想找潘金莲,但不能直接找,这时候出现了“中介-王婆”

接口:IWoman

public interface IWoman {public void makeEye();
}

实现类:PanJinLian

public class Panjinlian implements IWoman{@Overridepublic void makeEye() {System.out.println("潘金莲向你发送了一个邀请");}
}

实现类:WangPo

public class Wangpo implements IWoman{/*被代理对象*/private IWoman woman;public Wangpo(IWoman woman) {this.woman = woman;}public Wangpo() {}@Overridepublic void makeEye() {System.out.println("武大郎今天不在家");woman.makeEye();}
}

XiMenQing:

public class XiMenQing {public static void main(String[] args) {Panjinlian panjinlian = new Panjinlian();Wangpo wangpo = new Wangpo(panjinlian);wangpo.makeEye();}
}

上述案例,王婆就是代理,潘金莲就是被代理对象,西门庆找潘金莲就要先找王婆,达到了中介隔离的作用,而在代理中添加别的功能,不会对被代理对象产生代码污染,就实现了增加功能

基于接口动态代理jdk

演示:假如粉丝找歌手开演唱会,我们需要找到经纪人

接口:ISinger

public interface ISinger {public void Sing();
}

实现类:CaiXuKunImpl

public class CaiXuKunImp implements ISinger {@Overridepublic void Sing() {System.out.println("只因你太美");}
}

测试:Fans

public class Fans {public static void main(String[] args) {// 被代理对象ISinger caiXuKun = new CaiXuKunImp();ISinger jingjiren = (ISinger) Proxy.newProxyInstance(CaiXuKunImp.class.getClassLoader(), CaiXuKunImp.class.getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object obj = method.invoke(caiXuKun, args);System.out.println("跳舞");System.out.println("篮球");System.out.println("RAP");return obj;}});jingjiren.Sing();}
}

通过调用经纪人的sing(),蔡徐坤唱了一首只因你太美,

经纪人还做了增强功能,跳舞篮球Rap

基于子类的动态代理cglib

第三方插件,需要导入坐标

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

演示:粉丝通过经纪人找歌手

接口:ISinger

public interface ISinger {public void sing();
}

实现类:CaiXuKunImpl

public class CaiXuKunImp implements ISinger {@Overridepublic void sing() {System.out.println("oi oi oi");}
}

测试:Fans

public class Fans {public static void main(String[] args) {ISinger caixukun = new CaiXuKunImp();ISinger jingjiren = (ISinger) Enhancer.create(caixukun.getClass(), new InvocationHandler() {@Overridepublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {System.out.println("跳舞篮球RAP");Object object = method.invoke(caixukun, objects);return object;}});jingjiren.sing();}
}

对模拟转账业务升级

对代理模式有了概念和理解之后,就可以对上面的转账业务升级

静态代理实现升级改造

创建代理类:BeansFactory

public class BeansFactory {// 装配被代理对象private IAccountService toService;public void setToService(IAccountService toService) {this.toService = toService;}// 装配事务管理工具private TransactionUtil transactionUtil;public void setTransactionUtil(TransactionUtil transactionUtil) {this.transactionUtil = transactionUtil;}public IAccountService serviceProxy(){IAccountService serviceProxy = (IAccountService) Proxy.newProxyInstance(toService.getClass().getClassLoader(), toService.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object obj = null;try {transactionUtil.openTran();obj = method.invoke(toService, args);transactionUtil.commitTran();} catch (Exception e) {e.printStackTrace();}  finally {transactionUtil.closeTran();}return obj;}});return serviceProxy;}}

Service层实现类不需要再关注事务问题

public class AccountServiceImp implements IAccountService {IAccountDao dao;public void setDao(IAccountDao dao) {this.dao = dao;}@Overridepublic void save(Account account) {dao.save(account);}@Overridepublic void update(Account account) {dao.update(account);}@Overridepublic Account findByName(String name) {Account a = dao.findByName(name);return a;}@Overridepublic List<Account> findAll() {List<Account> all = dao.findAll();return all;}// 转账业务@Overridepublic void transfer(String sourceName, String targetName, int money) {// 查询俩个人的账户状态Account sourceAccount = dao.findByName(sourceName);Account targetAccount = dao.findByName(targetName);// 转账sourceAccount.setAmoney(sourceAccount.getAmoney()-money);targetAccount.setAmoney(targetAccount.getAmoney()+money);// 修改数据dao.update(sourceAccount);int a = 10/0;          // 模拟出现异常dao.update(targetAccount);}
}

配置文件中的修改:

<!--注入数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?serverTimezone=GMT"></property><property name="user" value="root"></property><property name="password" value="123456"></property>
</bean><!--注入连接工具类-->
<bean id="connectionUtil" class="com.dong.util.ConnectionUtil"><property name="dataSource" ref="dataSource"></property>
</bean><!--注入事务工具类-->
<bean id="transactionUtil" class="com.dong.util.TransactionUtil"><property name="connectionUtil" ref="connectionUtil"></property>
</bean><!--注入queryRunner-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner"><constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean><!--注入dao-->
<bean id="accountDaoImp" class="com.dong.dao.AccountDaoImp"><property name="queryRunner" ref="queryRunner"></property><property name="connectionUtil" ref="connectionUtil"></property>
</bean><!--注入service(被代理对象)-->
<bean id="accountServiceImp" class="com.dong.service.AccountServiceImp"><property name="dao" ref="accountDaoImp"></property>
</bean ><!--注入service代理业务-->
<bean id="accountServiceImpProxy" class="com.dong.service.AccountServiceImp" factory-bean="factory" factory-method="serviceProxy">
</bean><!--注入bean工厂-->
<bean id="factory" class="com.dong.factory.BeansFactory"><property name="toService" ref="accountServiceImp"></property><property name="transactionUtil" ref="transactionUtil"></property>
</bean><!--注入controller-->
<bean id="accountControllerImp" class="com.dong.controller.AccountControllerImp"><property name="service" ref="accountServiceImpProxy"></property>
</bean>

原来的service成为被代理对象,代理业务通过工厂造出,注入了事务管理对象和被代理业务对象,控制器中注入的对象变成被代理业务对象

Spring AOP

AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术

AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP 的作用及其优势

  • 作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强

  • 优势:减少重复代码,提高开发效率,并且便于维护

Spring AOP 基于动态代理实现

○ 如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和Proxy类);
○ 如果被代理的对象,没有实现某个接口,就无法使用 JDK Proxy 去进行代理了,这时被代理对象的子类来作为代理(Cglib动态代理的核心是MethodInterceptor接口和Enhancer类);

AOP主要用于

  1. 权限
  2. 日志
  3. 事务

AOP通知类型

AOP将抽取出来的共性功能称为通知;通知类型:以通知在上下文中的具体位置作为划分:

  1. 前置通知(Before)
  2. 返回通知(After-returning)
  3. 异常通知(After-throwing)
  4. 后置通知(After)
  5. 环绕通知(Around)

AOP连接点Join point

AOP将所有的方法都视为连接点,不管是接口里面的抽象方法,还是实现类里面的重写方法,都是连接点

AOP切点Pointcut

AOP将可能被抽取共性功能的方法称为切入点。切入点是连接点的子集

切点表达式配置语法

execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))
eg:execution(public void com.apesource.service.ServiceImp.findAll())
1.修饰符可以省略代表任意execution(返回值 包名称.类名称.方法名称(参数列表))
2.返回值可以使用“*”代表任意execution(* 包名称.类名称.方法名称(参数列表))
3.包名可以使用“*”代表任意名称execution(* *.*.*.类名称.方法名称(参数列表))
4.包名可以使用“..”代表任意个数execution(* *...类名称.方法名称(参数列表))
5.类名与方法名可以使用“*”代表任意execution(* *...*.*(参数列表))
6.参数列表可以使用".."代表任意个数任意类型execution(* *...*.*(..))如果有参数int======>intString===>java.lang.String

AOP目标对象Target

AOP目标对象(Target): 就是挖掉功能的方法对应的类生的对象,这种对象是无法直接完成最终工作的

AOP织入Weaving

AOP织入(Weaving):就是将挖掉的功能回填的动态过程

AOP切面:切点+通知

配置文件实现AOP

  1. 导入坐标
  2. 配置

演示:模拟一个业务,实现日志

  1. 导入坐标

    <dependencies><!--Spring--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.29</version></dependency><!-- aspectj (AOP) --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.7</version></dependency>
    </dependencies>
    
  2. 业务

    接口:

    public interface IService {public void save();public void delete();public void update();
    }
    

    实现类:

    public class ServiceImp implements IService {@Overridepublic void save() {System.out.println("新增咯");}@Overridepublic void delete() {System.out.println("删除咯");}@Overridepublic void update() {System.out.println("修改咯");}
    }
    
  3. 日志:

    public class Log {public void beforeLogger(){System.out.println("这是前置通知日志哦,时间:");}public void afterReturnningLogger(){System.out.println("这是返回通知日志哦,时间:");}public void exceptionLogger(){System.out.println("这是异常通知日志哦,时间:");}public void afterLogger(){System.out.println("这是后置通知日志哦,时间:");}public Object arroundLogger(ProceedingJoinPoint pjp){Object proceed =null;try {// 前置通知System.out.println("环绕通知----》前置通知");Object[] args = pjp.getArgs();proceed = pjp.proceed(args);// 返回通知System.out.println("环绕通知----》返回通知");} catch (Throwable throwable) {// 异常通知System.out.println("环绕通知----》异常通知");} finally {// 后置通知System.out.println("环绕通知----》后置通知");}return proceed;}
    }
    
  4. 配置文件:applicationContext.xml

    如果使用前置,返回,异常,后置通知,配置文件如下

    <!--注入Service-->
    <bean id="serviceImp" class="com.dong.service.ServiceImp"></bean>
    <!--注入log-->
    <bean id="log" class="com.dong.logs.Log"></bean><aop:config><aop:aspect id="aop" ref="log"><!--切点--><aop:pointcut id="dian" expression="execution(* com..dong.service.*.*(..))"/><!--前置通知--><aop:before method="beforeLogger" pointcut-ref="dian"></aop:before><!--返回通知--><aop:after-returning method="beforeLogger" pointcut-ref="dian"></aop:after-returning><!--异常通知--><aop:after-throwing method="exceptionLogger" pointcut-ref="dian"></aop:after-throwing><!--后置通知--><aop:after method="afterLogger" pointcut-ref="dian"></aop:after></aop:aspect>
    </aop:config>
    

    如果使用了环绕通知,则可以替代上面四种通知,配置文件如下

    <!--注入Service-->
    <bean id="serviceImp" class="com.dong.service.ServiceImp"></bean>
    <!--注入log-->
    <bean id="log" class="com.dong.logs.Log"></bean><aop:config><aop:aspect id="aop" ref="log"><!--切点--><aop:pointcut id="dian" expression="execution(* com..dong.service.*.*(..))"/><!--环绕通知--><aop:around method="arroundLogger" pointcut-ref="dian"></aop:around></aop:aspect>
    

注释实现AOP

  1. 导坐标,spring-context和aspectjweaver坐标

  2. 业务:

    接口:

    public interface IService {public void save();public void delete();public void update();
    }
    

    实现类:

    @Service
    public class ServiceImp implements IService {@Overridepublic void save() {System.out.println("新增咯");}@Overridepublic void delete() {System.out.println("删除咯");}@Overridepublic void update() {System.out.println("修改咯");}
    }
    
  3. 日志:

    @Component
    @Aspect
    public class Log {@Pointcut(value = "execution(* com.dong.service.*.*(..))")public void dian(){};@Before("dian()")public void beforeLog(){System.out.println("这是前置日志");}@AfterReturning("dian()")public void afterReturnningLog(){System.out.println("这是返回日志");}@AfterThrowing("dian()")public void exceptionLog(){System.out.println("这是异常日志");}@After("dian()")public void afterLog(){System.out.println("这是后置日志");}@Around("dian()")public Object arroundLog(ProceedingJoinPoint pjp){Object proceed =null;try {System.out.println("环绕日志----》前置日志");Object[] args = pjp.getArgs();proceed = pjp.proceed(args);System.out.println("环绕日志----》返回");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("环绕日志----》异常");} finally {System.out.println("环绕日志----》后置");}return proceed;}
    }
    
  4. 配置文件中,要扫包,并开启AOP

    <!--扫包-->
    <context:component-scan base-package="com.dong"></context:component-scan>
    <!--注解驱动-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    

Spring整合Mybatis

  1. 导坐标

    <dependencies><!--spring容器--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.29</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.5</version></dependency><!--springJDBC--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.9.RELEASE</version></dependency><!--数据源--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.21</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.29</version></dependency>
    </dependencies>
    
  2. Bean实体类:Account

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @Component
    public class Account {private int aid;private String aname;private int amoney;public Account(String aname, int amoney) {this.aname = aname;this.amoney = amoney;}
    }
    
  3. Dao层

    public interface IAccountDao {@Insert("insert into acount(aname,amoney) values(#{aname},#{amoney})")public void save(Account account);@Update("update acount set aname=#{aname} , amoney=#{amoney} where aid = #{aid}")public void update(Account account);@Select("select * from acount")public List<Account> selectAll();@Select("select * from acount where aname=#{v}")public Account selectByName(String name);}
    
  4. Service层:

    接口:

    public interface IAccountService {public void save(Account account);public void update(Account account);public Account selectByName(String name);public List<Account> selectAll();
    }
    

    实现类:

    @Service
    public class AccountServiceImpl  implements IAccountService{@Autowiredprivate IAccountDao dao;@Overridepublic void save(Account account) {dao.save(account);}@Overridepublic void update(Account account) {dao.update(account);}@Overridepublic Account selectByName(String name) {Account account = dao.selectByName(name);return account;}@Overridepublic List<Account> selectAll() {List<Account> accounts = dao.selectAll();return accounts;}
    }
    
  5. Controller层:

    接口:

    public interface IAccountController {public void save(Account account);public void update(Account account);public Account selectByName(String name);public List<Account> selectAll();
    }
    

    实现类:

    @Controller
    public class AccountConreollerImpl implements IAccountController {@Autowiredprivate IAccountService service;@Overridepublic void save(Account account) {service.save(account);}@Overridepublic void update(Account account) {service.update(account);}@Overridepublic Account selectByName(String name) {Account account = service.selectByName(name);return account;}@Overridepublic List<Account> selectAll() {List<Account> accounts = service.selectAll();return accounts;}
    }
    
  6. 配置文件

    Mybatis的配置文件:Mybatis.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration><!--1.数据源==交给spring容器2.事务管理==交给spring容器3.mapper映射器注册--></configuration>
    

    Spring的配置文件:applicationContext.xml

    <?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--注入数据源--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/spring?serverTimezone=GMT"></property><property name="username" value="root"></property><property name="password" value="123456"></property></bean><!--配置sqlSessionFactory--><bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property><property name="configLocation" value="classpath:mybatisConfig.xml"></property></bean><!--配置mapper映射器,生成代理对象注入容器--><bean id="configurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.dong.dao"></property></bean><!--扫包--><context:component-scan base-package="com.dong"></context:component-scan>
    </beans>
    

    注入mapper映射器后,dao层就不需要再注入容器了

以上步骤完成,Spring就成功整合了Mybatis

Spring任务调度(spring task)

任务调度

​ 可以用于程序运行时设置在某些固定的时刻执行特定的操作,比如设置调度任务在凌晨的时候自动同步数据等等

实现技术:spring task

实现spring task任务调布只需要导入spring context坐标即可,不需要额外导入其他坐标,只需要在spring主配置文件中配置

配置文件实现任务调度

  1. 假如被调度的任务输出信息

    public class MyTask {public void task1(){System.out.println("task1:"+new Date());}public void task2(){System.out.println("task2:"+new Date());}
    }
    
  2. spring主配置文件

    <?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:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"><!--注入任务--><bean id="task" class="com.dong.MyTask"></bean><!--创建调度线程池--><task:scheduler id="poolTaskScheduler" pool-size="10"></task:scheduler><!--配置任务调度--><task:scheduled-tasks scheduler="poolTaskScheduler"><!--任务方法   cron表达式:实现触发任务的策略--><task:scheduled ref="task" method="task1" cron="0-5 * * * * *"/><task:scheduled ref="task" method="task2" cron="3/3 * * * * *"/></task:scheduled-tasks>
    </beans>
    
    • 需要把被调度的任务对象注入容器
    • 调度线程池配不配置都可以
    • <task:scheduled-tasks></task:scheduled-tasks>标签中调度线程池若没配置就不需要写属性,想要调度的方法就可以在配置标签之间写,ref写注入的任务,method写调度任务的方法,cron表达式配置触发任务的策略
  3. 测试(让程序程序运行)

    public class Test01 {public static void main(String[] args) {ApplicationContext app = new ClassPathXmlApplicationContext("applicationcontext.xml");}
    }
    
  4. 控制台输出效果

    在这里插入图片描述

    上述配置的task1任务的cron表达式:每分钟前五秒调一次

    ​ task2任务的cron表达式:第3秒开始,每隔三秒钟调一次

cron表单式

在这里插入图片描述

cron表达式从左到右共有七位,分别代表:

秒、分、小时、日期、月份、星期、年份

cron表达式在线工具生成器网址

注解实现任务调度

  1. 导入坐标spring context

  2. 任务调度对象

    需要写@Component注解,注入容器

    ​ @Scheduled注解,表示调度任务,括号中写cron表达式

    @Component
    public class MyJob {@Scheduled(cron = "* * * * * *")public void myjob1(){System.out.println("Hacker Dong");}
    }
    
  3. 配置文件

    <?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:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"><!--扫包--><context:component-scan base-package="com.dong"></context:component-scan><!--配置任务调度开启--><task:annotation-driven></task:annotation-driven>
    </beans>
    
    • 配置扫包
    • 配置开启任务调度
  4. 测试

    public class Test01 {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");}
    }
    

Spring注解实现事务管理

spring实现事务管理就不再需要自己写事务管理工具类,只需要在业务上添加注解@Transactional

  1. 导入坐标

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.dong</groupId><artifactId>SpringAOP_transaction</artifactId><version>1.0-SNAPSHOT</version><dependencies><!--spring容器--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.29</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.5</version></dependency><!--springJDBC--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.9.RELEASE</version></dependency><!--数据源--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.21</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.29</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.0.3.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.7</version></dependency></dependencies></project>
    
  2. Bean实体类、Dao、Service、Controller三层

    Bean:

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @Component
    public class Account implements Serializable {private int aid;private String aname;private int amoney;
    }
    

    dao:

    public interface IAccountDao {@Insert("insert into acount(aname,amoney) values(#{aname},#{amoney})")public void save(Account account);@Update("update acount set aname=#{aname} , amoney=#{amoney} where aid = #{aid}")public void update(Account account);@Select("select * from acount where aname=#{v}")public Account selectByName(String name);@Select("select * from acount")public List<Account> selectAll();
    }
    

    Service层:

    IAccountSerivce:

    public interface IAccountSerivce {public void save(Account account);public void update(Account account);public Account selectByName(String name);public List<Account> selectAll();public void zhuanzhang(String user1,String user2,int money);
    }
    

    AccountServiceImp:

    @Service
    @Transactional         // spring事务管理
    public class AccountServiceImp implements IAccountSerivce {@Autowiredprivate IAccountDao dao;@Overridepublic void save(Account account) {dao.save(account);}@Overridepublic void update(Account account) {dao.update(account);}@Overridepublic Account selectByName(String name) {Account account = dao.selectByName(name);return account;}@Overridepublic List<Account> selectAll() {List<Account> accounts = dao.selectAll();return accounts;}@Overridepublic void zhuanzhang(String user1, String user2, int money) {Account account1 = dao.selectByName(user1);Account account2 = dao.selectByName(user2);account1.setAmoney(account1.getAmoney()-money);account2.setAmoney(account2.getAmoney()+money);dao.update(account1);dao.update(account2);}
    }
    

    Controller层:

    IAccountController:

    public interface IAccountController {public void save(Account account);public void update(Account account);public Account selectByName(String name);public List<Account> selectAll();public void zhuanzhang(String user1,String user2,int money);
    }
    

    AccountControllerImp:

    @Controller
    public class AccountControllerImp implements IAccountController{@Autowiredprivate IAccountSerivce service;@Overridepublic void save(Account account) {service.save(account);}@Overridepublic void update(Account account) {service.update(account);}@Overridepublic Account selectByName(String name) {Account account = service.selectByName(name);return account;}@Overridepublic List<Account> selectAll() {List<Account> accounts = service.selectAll();return accounts;}@Overridepublic void zhuanzhang(String user1, String user2, int money) {service.zhuanzhang(user1,user2,money);}
    }
    
  3. 配置文件:

    mybatis的配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration><!--1.数据源==交给spring容器2.事务管理==交给spring容器3.mapper映射器注册--></configuration>
    

    spring主配置文件:

    <?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.alibaba.com/schema/stat http://www.alibaba.com/schema/stat.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!--注入数据源--><bean id="data" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/spring?serverTimezone=GMT"></property><property name="username" value="root"></property><property name="password" value="123456"></property></bean><!--配置sqlSessionFactory--><bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="data"></property><property name="configLocation" value="classpath:mybatisConfig.xml"></property></bean><!--配置mapper映射器,生成代理对象注入容器--><bean id="configurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.dong.dao"></property></bean><!--扫包--><context:component-scan base-package="com.dong"></context:component-scan><!--配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入DataSource--><property name="dataSource" ref="data"></property></bean><!--开启spring对注解事务管理的支持--><tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven></beans>
    

    注意事项:

    • 数据源,SqlSessionFactoryBean需要配置
    • 配置mapper映射器,dao层不需要再注入容器
    • 扫包
    • 配置事务管理器
      • 需要注入数据源
      • 需要开启spring对注解事务管理的支持

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/174309.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ajax学习笔记第4天

做决定之前仔细考虑&#xff0c;一旦作了决定就要勇往直前、坚持到底&#xff01; 【1 模仿百度招聘】 整个流程展示&#xff1a; 1.文件目录 2.页面效果展示及代码 data中的page1数据展示 2.1 主页 index.html:index里面代码部分解释 underscore.js :模板页面的相关代码 &…

【Linux】深入理解系统文件操作(1w字超详解)

1.系统下的文件操作&#xff1a; ❓是不是只有C\C有文件操作呢&#xff1f;&#x1f4a1;Python、Java、PHP、go也有&#xff0c;他们的文件操作的方法是不一样的啊 1.1对于文件操作的思考&#xff1a; 我们之前就说过了&#xff1a;文件内容属性 针对文件的操作就变成了对…

[SpringCloud] Eureka 与 Ribbon 简介

目录 一、服务拆分 1、案例一&#xff1a;多端口微服务 2、案例二&#xff1a;服务远程调用 二、Eureka 1、Eureka 原理分析 2、Eureka 服务搭建&#xff08;注册 eureka 服务&#xff09; 3、Eureka 服务注册&#xff08;注册其他服务&#xff09; 4、Eureka 服务发现…

基于Electron27+React18+ArcoDesign客户端后台管理EXE

基于electron27.xreact18搭建电脑端exe后台管理系统模板 electron-react-admin 基于electron27整合vite.jsreact18搭建桌面端后台管理程序解决方案。 前几天有分享electron27react18创建跨平台应用实践&#xff0c;大家感兴趣可以去看看。 https://blog.csdn.net/yanxinyun1990…

OpenAI 组建安全 AGI 新团队!应对AI“潘多拉魔盒”

夕小瑶科技说 原创 作者 | 小戏 一旦谈及未来 AI&#xff0c;除了天马行空的科幻畅想&#xff0c;不可避免的也有未来 AI 时代的末日预言。从 AI 武器化到 AI 欺骗&#xff0c;从邪恶 AI 到 AI 掌权&#xff0c;人工智能&#xff0c;尤其是通用人工智能的风险始终都清清楚楚的…

【100天精通Python】Day72:Python可视化_一文掌握Seaborn库的使用《二》_分类数据可视化,线性模型和参数拟合的可视化,示例+代码

目录 1. 分类数据的可视化 1.1 类别散点图&#xff08;Categorical Scatter Plot&#xff09; 1.2 类别分布图&#xff08;Categorical Distribution Plot&#xff09; 1.3 类别估计图&#xff08;Categorical Estimate Plot&#xff09; 1.4 类别单变量图&#xff08;Cat…

3 tensorflow构建的模型详解

上一篇&#xff1a;2 用TensorFlow构建一个简单的神经网络-CSDN博客 1、神经网络概念 接上一篇&#xff0c;用tensorflow写了一个猜测西瓜价格的简单模型&#xff0c;理解代码前先了解下什么是神经网络。 下面是百度AI对神经网络的解释&#xff1a; 这里不赘述太多概念相关的…

【Apache Flink】基于时间和窗口的算子-配置时间特性

文章目录 前言配置时间特性将时间特性设置为事件时间时间戳分配器周期性水位线分配器创建一个实现AssignerWithPeriodicWatermarks接口的类&#xff0c;目的是为了周期性生成watermark 定点水位线分配器示例 参考文档 前言 Apache Flink 它提供了多种类型的时间和窗口概念&…

NSS刷题 js前端修改 os.path.join漏洞

打算刷一遍nssweb题&#xff08;任重道远&#xff09; 前面很简单 都是签到题 这里主要记录一下没想到的题目 [GDOUCTF 2023]hate eat snake js前端修改 这里 是对js的处理 有弹窗 说明可能存在 alert 我们去看看js 这里进行了判断 如果 getScore>-0x1e9* 我们结合上面…

【MATLAB源码-第61期】基于蜣螂优化算法(DBO)的无人机栅格地图路径规划,输出最短路径和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 蜣螂优化算法&#xff08;Dung Beetle Optimization, DBO&#xff09;是一种模拟蜣螂在寻找食物和进行导航的过程的优化算法。蜣螂是一种能够将粪球滚到合适地点的昆虫&#xff0c;它们利用天空中的光线和自身的感知能力来确…

Go 开发IDE全览:GoLand VS VSCode全面解析

一、引言 在软件开发的世界里&#xff0c;开发环境的选择与配置是成功项目的基础之一。特别是在Go&#xff08;又名Golang&#xff09;这样一个逐渐获得主流认同、在微服务和云计算领域有着广泛应用的编程语言中&#xff0c;选择合适的开发工具就显得尤为重要。虽然Go语言自身…

【MySQL】 复合查询 | 内外连接

文章目录 1. 复合查询多表笛卡尔积自连接在where子句使用子查询单行子查询多行子查询in关键字all关键字any关键字 多列子查询 在from子句中使用子查询合并查询unionunion all 2. 内连接3. 外连接左外连接右外连接 1. 复合查询 多表笛卡尔积 显示雇员名、雇员工资以及所在部门…

LeetCode2741.特别的排列 状压

暴力枚举的话是n&#xff01; 考虑状压DP&#xff0c;其实就是用二进制表示状态 再进行暴力 同时加一个记忆化就好了 这里有常用技巧&#xff1a; 全集&#xff08;1<<n&#xff09;-1 增加某个元素 x | (1<<i) 删除某个元素 x & ~(1<<i) const i…

Java进阶(Set)——面试时Set常见问题解读 结合源码分析

前言 List、Set、HashMap作为Java中常用的集合&#xff0c;需要深入认识其原理和特性。 本篇博客介绍常见的关于Java中Set集合的面试问题&#xff0c;结合源码分析题目背后的知识点。 关于List的博客文章如下&#xff1a; Java进阶&#xff08;List&#xff09;——面试时L…

最短路径:迪杰斯特拉算法

简介 英文名Dijkstra 作用&#xff1a;找到路中指定起点到指定终点的带权最短路径 核心步骤 1&#xff09;确定起点&#xff0c;终点 2&#xff09;从未走过的点中选取从起点到权值最小点作为中心点 3&#xff09;如果满足 起点到中心点权值 中心点到指定其他点的权值 < 起…

Java学习_day05_数组

文章目录 一维数组概念初始化默认值动态赋值 二维数组概念初始化遍历数组 一维数组 数组是目前学习Java中&#xff0c;遇到的第一个引用对象。即在变量的存储空间中&#xff0c;存储的不再是数值&#xff0c;而是内存地址。这个内存地址指向实际对象的存储空间地址。 概念 …

Cocos Creator 中使用装饰器进行自动绑定

推荐一个偷懒的方式&#xff0c;使用装饰器自动绑定节点到脚本的属性 背景 用 Cocos Creator 写脚本组件的时候&#xff0c;有时需要场景中一个节点作为这个脚本的属性值。 按照官方文档推荐的方法&#xff0c;需要以下两步 添加一个 property 属性&#xff0c;在场景中拖入这个…

三维地图数据共享与统一存储

这家总部位于北京的高新企业是一家致力于三维数字地理技术的领军企业&#xff0c;提供中国领先的三维数据获取服务&#xff0c;并依据三维数据自动建模云计算服务、提供全国性的地图与位置服务。这项技术其实我们每天都有可能用到&#xff0c;例如百度地图、高德地图就属于三维…

基于标签的电影推荐算法研究_张萌

&#xff12; 标签推荐算法计算过程 &#xff12;&#xff0e;&#xff11; 计算用户对标签的喜好程度 用户对一个标签的认可度可以使用二元关系来表示&#xff0c;这种关系只有“是”“否”两种结果&#xff0c;实际上难以准确地表达出用 户对物品的喜好程度。因此&#x…

BUUCTF qr 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 这是一个二维码&#xff0c;谁用谁知道&#xff01; 密文&#xff1a; 下载附件&#xff0c;得到一张二维码图片。 解题思路&#xff1a; 1、这是一道签到题&#xff0c;扫描二维码得到flag。 flag&#xff1a;…