当前位置: 首页 > news >正文

Spring JdbcTemplate 和 事务

JdbcTemplate概述

JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。
在这里插入图片描述
按如下项目结构准备 maven jar项目即可
在这里插入图片描述
导入依赖

 <dependencies><!--spring核心容器包--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.5</version></dependency><!--spring切面包--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.5</version></dependency><!--aop联盟包--><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><!--德鲁伊连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.22</version></dependency><!--springJDBC包--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.5</version></dependency><!--spring事务控制包--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.3.5</version></dependency><!--spring orm 映射依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>5.3.5</version></dependency><!--Apache Commons日志包--><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><!--Junit单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>test</scope></dependency><!--lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency></dependencies>

准备JDBC.properties

jdbc_username=root
jdbc_password=root
jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true

准备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:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"xmlns:util="http://www.springframework.org/schema/util"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd
"><!--spring 注解扫描--><context:component-scan base-package="com.msb"/><!--读取jdbc配置文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--配置德鲁伊连接池--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="username" value="${jdbc_username}"></property><property name="password" value="${jdbc_password}"></property><property name="url" value="${jdbc_url}"></property><property name="driverClassName" value="${jdbc_driver}"></property></bean><!--配置JDBCTemplate对象,并向里面注入DataSource--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--通过set方法注入连接池--><property name="dataSource" ref="dataSource"></property></bean>
</beans>

单个数据操作
准备实体类

package com.msb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;@AllArgsConstructor
@NoArgsConstructor
@Data
public class Emp implements Serializable{private Integer empno;private String ename;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;
}

准备service层接口和实现类

package com.msb.service;
import com.msb.pojo.Emp;
import java.util.List;public interface EmpService {int findEmpCount();Emp findByEmpno(int empno);List<Emp> findByDeptno(int deptno);int  addEmp(Emp emp);int updateEmp(Emp emp);int deleteEmp( int empno);
}
package com.msb.service.impl;
import com.msb.dao.EmpDao;
import com.msb.pojo.Emp;
import com.msb.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class EmpServiceImpl implements EmpService {@Autowiredprivate EmpDao empDao;@Overridepublic int findEmpCount() {return empDao.findEmpCount();}@Overridepublic Emp findByEmpno(int empno) {return empDao.findByEmpno( empno);}@Overridepublic List<Emp> findByDeptno(int deptno) {return empDao.findByDeptno( deptno);}@Overridepublic int addEmp(Emp emp) {return empDao.addEmp(emp);}@Overridepublic int updateEmp(Emp emp) {return empDao.updateEmp(emp);}@Overridepublic int deleteEmp(int empno) {return empDao.deleteEmp(empno);}
}

准备dao层接口和实现类

package com.msb.dao;
import com.msb.pojo.Emp;
import java.util.List;public interface EmpDao {int findEmpCount();Emp findByEmpno(int empno);List<Emp> findByDeptno(int deptno);int addEmp(Emp emp);int updateEmp(Emp emp);int deleteEmp(int empno);
}
package com.msb.dao.impl;
import com.msb.dao.EmpDao;
import com.msb.pojo.Emp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;@Repository
public class EmpDaoImpl implements EmpDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int findEmpCount() {/*查询员工个数* queryForObject 两个参数* 1 SQL语句* 2 返回值类型** */Integer empCount = jdbcTemplate.queryForObject("select count(1) from emp", Integer.class);return empCount;}@Overridepublic Emp findByEmpno(int empno) {/** 查询单个员工对象* queryForObject三个参数* 1 SQL语句* 2 RowMapper接口的实现类对象,用于执行返回的结果用哪个类来进行封装 ,实现类为BeanPropertyRowMapper* 3 SQL语句中需要的参数 (可变参数)* */BeanPropertyRowMapper<Emp> rowMapper =new BeanPropertyRowMapper<>(Emp.class);Emp emp = jdbcTemplate.queryForObject("select * from emp where empno =?", rowMapper, empno);return emp;}@Overridepublic List<Emp> findByDeptno(int deptno) {/** 查询单个员工对象* query三个参数* 1 SQL语句* 2 RowMapper接口的实现类对象,用于执行返回的结果用哪个类来进行封装 ,实现类为BeanPropertyRowMapper* 3 SQL语句中需要的参数 (可变参数)* */BeanPropertyRowMapper<Emp> rowMapper =new BeanPropertyRowMapper<>(Emp.class);List<Emp> emps = jdbcTemplate.query("select * from emp where deptno =?", rowMapper, deptno);return emps;}@Overridepublic int addEmp(Emp emp) {/*增删改* 统统用update方法 两个参数* 1 SQL语句* 2 SQL语句需要的参数 (可变参数)** */String sql ="insert into emp values(DEFAULT ,?,?,?,?,?,?,?)";Object[] args ={emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno()};return jdbcTemplate.update(sql,args);}@Overridepublic int updateEmp(Emp emp) {String sql ="update emp set ename =? , job =?, mgr=? , hiredate =?, sal=?, comm=?, deptno =? where empno =?";Object[] args ={emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno(),emp.getEmpno()};return jdbcTemplate.update(sql,args);}@Overridepublic int deleteEmp(int empno) {String sql ="delete  from emp where empno =?";return jdbcTemplate.update(sql, empno);}
}

测试代码

package com.msb.test;
import com.msb.pojo.Emp;
import com.msb.service.EmpService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
import java.util.List;public class Test1 {@Testpublic void testEmpService(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");EmpService empService = context.getBean(EmpService.class);// 查询员工个数/*int empCount = empService.findEmpCount();System.out.println(empCount);*/// 根据员工编号查询员工对象/* Emp byEmpno = empService.findByEmpno(7521);System.out.println(byEmpno);*//*根据部门编号查询多个员工对象集合*//*List<Emp> emps = empService.findByDeptno(20);emps.forEach(System.out::println);*//*增加员工信息*//*int rows = empService.addEmp(new Emp(null, "TOM", "SALESMAN", 7521, new Date(), 2000.0, 100.0, 10));System.out.println(rows);*//*根据员工编号修改员工信息*//*int rows = empService.updateEmp(new Emp(7939, "JERRY", "MANAGER", 7839, new Date(), 3000.0, 0.0, 20));System.out.println(rows);*//*根据员工编号删除员工信息*//*int rows = empService.deleteEmp(7939);System.out.println(rows);*/}
}

批量操作
1 批量增加
2 批量修改
3 批量删除

实体类

package com.msb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@AllArgsConstructor
@NoArgsConstructor
@Data
public class Dept implements Serializable {private Integer deptno;private String dname;private String loc;
}

DeptService

package com.msb.service;
import com.msb.pojo.Dept;
import java.util.List;public interface DeptService {int[] deptBatchAdd(List<Dept> depts);int[] deptBatchUpdate(List<Dept> depts);int[] deptBatchDelete(List<Integer> deptnos);
}
package com.msb.service.impl;
import com.msb.dao.DeptDao;
import com.msb.pojo.Dept;
import com.msb.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptDao deptDao;@Overridepublic int[] deptBatchAdd(List<Dept> depts) {return deptDao.deptBatchAdd(depts);}@Overridepublic int[] deptBatchUpdate(List<Dept> depts) {return  deptDao.deptBatchUpdate(depts);}@Overridepublic int[] deptBatchDelete(List<Integer> deptnos) {return  deptDao.deptBatchDelete(deptnos);}
}

DeptDao

package com.msb.dao;
import com.msb.pojo.Dept;
import java.util.List;public interface DeptDao {int[] deptBatchAdd(List<Dept> depts);int[] deptBatchUpdate(List<Dept> depts);int[] deptBatchDelete(List<Integer> deptnos);
}
package com.msb.dao.impl;
import com.msb.dao.DeptDao;
import com.msb.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.LinkedList;
import java.util.List;@Repository
public class DeptDaoImpl implements DeptDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int[] deptBatchAdd(List<Dept> depts) {String sql ="insert into dept values(DEFAULT,?,?)";List<Object[]> args =new LinkedList<>();for (Dept dept : depts) {Object[] arg ={dept.getDname(),dept.getLoc()};args.add(arg);}return jdbcTemplate.batchUpdate(sql, args);}@Overridepublic int[] deptBatchUpdate(List<Dept> depts) {String sql ="update dept set dname =? ,loc =? where deptno=?";List<Object[]> args =new LinkedList<>();for (Dept dept : depts) {Object[] arg ={dept.getDname(),dept.getLoc(),dept.getDeptno()};args.add(arg);}return jdbcTemplate.batchUpdate(sql, args);}@Overridepublic int[] deptBatchDelete(List<Integer> deptnos) {String sql ="delete from dept where deptno =?";List<Object[]> args =new LinkedList<>();for (Integer deptno : deptnos) {Object[] arg ={deptno};args.add(arg);}return jdbcTemplate.batchUpdate(sql, args);}
}

测试

package com.msb.test;
import com.msb.pojo.Dept;
import com.msb.service.DeptService;
import com.msb.service.EmpService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class Test2 {@Testpublic void testBatchAdd(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");DeptService deptService = context.getBean(DeptService.class);List<Dept> depts =new ArrayList<>();for (int i = 0; i < 10; i++) {depts.add(new Dept(null,"name"+i,"loc"+i));}int[] ints = deptService.deptBatchAdd(depts);System.out.println(Arrays.toString(ints));}@Testpublic void testBatchUpdate(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");DeptService deptService = context.getBean(DeptService.class);List<Dept> depts =new ArrayList<>();for (int i = 51; i <=60; i++) {depts.add(new Dept(i,"newname","newLoc"));}int[] ints = deptService.deptBatchUpdate(depts);System.out.println(Arrays.toString(ints));}@Testpublic void testBatchDelete(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");DeptService deptService = context.getBean(DeptService.class);List<Integer> deptnos =new ArrayList<>();for (int i = 51; i <=69; i++) {deptnos.add(i);}int[] ints = deptService.deptBatchDelete(deptnos);System.out.println(Arrays.toString(ints));}
}

事务

1.事务的概念

事务(Transaction)指的是一个操作序列,该操作序列中的多个操作要么都做,要么都不做,是一个不可分割的工作单位,是数据库环境中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

目前常用的存储引擎有InnoDB(MySQL5.5以后默认的存储引擎)和MyISAM(MySQL5.5之前默认的存储引擎),其中InnoDB支持事务处理机制,而MyISAM不支持。

2.事务的特性

事务处理可以确保除非事务性序列内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的序列,可以简化错误恢复并使应用程序更加可靠。

但并不是所有的操作序列都可以称为事务,这是因为一个操作序列要成为事务,必须满足事务的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。这四个特性简称为ACID特性。
在这里插入图片描述

  1. 原子性

原子是自然界最小的颗粒,具有不可再分的特性。事务中的所有操作可以看做一个原子,事务是应用中不可再分的最小的逻辑执行体。

使用事务对数据进行修改的操作序列,要么全部执行,要么全不执行。通常,某个事务中的操作都具有共同的目标,并且是相互依赖的。如果数据库系统只执行这些操作中的一部分,则可能会破坏事务的总体目标,而原子性消除了系统只处理部分操作的可能性。

2)一致性

一致性是指事务执行的结果必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库中只包含事务成功提交的结果时,数据库处于一致性状态。一致性是通过原子性来保证的。

例如:在转账时,只有保证转出和转入的金额一致才能构成事务。也就是说事务发生前和发生后,数据的总额依然匹配。

  1. 隔离性

隔离性是指各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务,都是隔离的。也就是说:并发执行的事务之间既不能看到对方的中间状态,也不能相互影响。

例如:在转账时,只有当A账户中的转出和B账户中转入操作都执行成功后才能看到A账户中的金额减少以及B账户中的金额增多。并且其他的事务对于转账操作的事务是不能产生任何影响的。

4)持久性

持久性指事务一旦提交,对数据所做的任何改变,都要记录到永久存储器中,通常是保存进物理数据库,即使数据库出现故障,提交的数据也应该能够恢复。但如果是由于外部原因导致的数据库故障,如硬盘被损坏,那么之前提交的数据则有可能会丢失。

3.事务的并发问题

脏读(Dirty read)

当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
在这里插入图片描述
不可重复读

(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
在这里插入图片描述
幻读

(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

在这里插入图片描述
不可重复度和幻读区别:

不可重复读的重点是修改,幻读的重点在于新增或者删除。

解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

例1(同样的条件, 你读取过的数据, 再次读取出来发现值不一样了 ):事务1中的A先生读取自己的工资为 1000的操作还没完成,事务2中的B先生就修改了A的工资为2000,导 致A再读自己的工资时工资变为 2000;这就是不可重复读。

例2(同样的条件, 第1次和第2次读出来的记录数不一样 ):假某工资单表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,共查到4条记录,这时事务2又插入了一条工资大于3000的记录,事务1再次读取时查到的记录就变为了5条,这样就导致了幻读

4.事务的隔离级别

事务的隔离级别用于决定如何控制并发用户读写数据的操作。数据库是允许多用户并发访问的,如果多个用户同时开启事务并对同一数据进行读写操作的话,有可能会出现脏读、不可重复读和幻读问题,所以MySQL中提供了四种隔离级别来解决上述问题。

事务的隔离级别从低到高依次为READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ以及SERIALIZABLE,隔离级别越低,越能支持高并发的数据库操作。
在这里插入图片描述
spring中可以使用如下方式实现事务的控制

1 编程式(不推荐)

2 声明式(掌握)

1)注解(简单,必会)

2)XML配置(繁琐,了解)

demo搭建
通过张三给李四转账案例演示事务的控制
1 数据库中准备表格
在这里插入图片描述
applicationContext.xml
jdbc.properties 如上边项目配置
项目中准备实体类

package com.msb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@AllArgsConstructor
@NoArgsConstructor
@Data
public class Account implements Serializable {private Integer id;private String name;private Integer money;
}

准备DAO层,创建一个根据id修改money的方法

package com.msb.dao;public interface AccountDao {int transMoney(int id,int money);
}
package com.msb.dao.impl;
import com.msb.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;@Repository
public class AccountDaoImpl implements AccountDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int transMoney(int id, int money) {String sql ="update account set money =money +? where id =?";return jdbcTemplate.update(sql,money,id);}
}

准备Service,创建一个转账的业务方法

package com.msb.service;public interface AccountService {int transMoney(int from ,int to,int money);
}
package com.msb.service.impl;
import com.msb.dao.AccountDao;
import com.msb.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Overridepublic int transMoney(int from, int to, int money) {int rows=0;rows+=accountDao.transMoney(from, 0 - money);       rows+=accountDao.transMoney(to, money);        return rows;}
}

测试代码,测试转账

package com.msb.test;
import com.msb.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestTx {@Test()public void testTransaction(){ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");AccountService accountService = context.getBean(AccountService.class);int rows = accountService.transMoney(1, 2, 100);System.out.println(rows);}}

基于注解方式实现

Spring声明式事务的实现方式,底层就是AOP,AOP的底层就是动态代理

Spring事务管理相关的API

事务管理器接口: PlatformTransactionManager 针对不同的框架,提供了不同的实现类
在这里插入图片描述
注解方式实现事务控制
在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:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"xmlns:util="http://www.springframework.org/schema/util"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd
"><!--spring 注解扫描--><context:component-scan base-package="com.msb"/><!--读取jdbc配置文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--配置德鲁伊连接池--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="username" value="${jdbc_username}"></property><property name="password" value="${jdbc_password}"></property><property name="url" value="${jdbc_url}"></property><property name="driverClassName" value="${jdbc_driver}"></property></bean><!--配置JDBCTemplate对象,并向里面注入DataSource--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--通过set方法注入连接池--><property name="dataSource" ref="dataSource"></property></bean><!--配置一个事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--将数据源注入事务管理器--><property name="dataSource"  ref="dataSource"></property></bean><!--开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

在Service层中添加事务的注解

package com.msb.service.impl;
import com.msb.dao.AccountDao;
import com.msb.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
//@Transactional //加在类上,代表类中的所有方法都添加了事务控制
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Override@Transactional// 放在方法上,就是仅仅对当前方法增加了事务控制public int transMoney(int from, int to, int money) {int rows=0;rows+=accountDao.transMoney(from, 0 - money);int i =1/0;rows+=accountDao.transMoney(to, money);return rows;}
}

再次测试,就算是service方法运行出现异常,自动会回滚,如果没有,那么自动提交

@Transactional 注解的一些参数和参数的含义
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_UNCOMMITTED,readOnly = true,rollbackFor = ClassCastException.class,noRollbackFor = NullPointerException.class,timeout = 10)

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";String[] label() default {};Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default -1;String timeoutString() default "";boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};
}

propagation 事务的传播行为(面试)
多事务方法之间调用,事务是如何管理的
在这里插入图片描述
在这里插入图片描述
如果service层 add方法调用了 addDept和addEmp两个方法

PROPAGATION_REQUIRED
如果add方法有事务,那么addDept和addEmp就加入到add方法里的事务
如果add方法没有事务,那么就新建一个事务,将addDept和addEmp加入到这个新的事务中

PROPAGATION_REQUIRES_NEW
无论add是否有事务,都建立一个新的事务,所有的方法都加入到新的事务中,add原来的事务就不用了

isolation 事务的隔离级别

  1. DEFAULT (默认)
    这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。
    MySQL默认REPEATABLE_READ
    Oracle默认READ_COMMITTED

  2. READ_UNCOMMITTED (读未提交)
    这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

  3. READ_COMMITTED (读已提交)
    保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

  4. REPEATABLE_READ (可重复读)
    这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

  5. SERIALIZABLE(串行化)
    这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。

timeout 超时时间
事务一定要在多长时间之内提交,如果不提交就会回滚

readOnly 只读事务
事务是否只能读取数据库的数据,如果为true,则不允许进行增删改

rollbackFor 指定发生回滚的异常
当方法发生哪些异常时才会回滚

noRollbackFor 指定不发生回滚的异常
当方法发生哪些异常时,不会回滚

事务的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:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"xmlns:util="http://www.springframework.org/schema/util"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd
"><context:component-scan base-package="com.msb"/><!--读取jdbc配置文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--配置德鲁伊连接池--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="username" value="${jdbc_username}"></property><property name="password" value="${jdbc_password}"></property><property name="url" value="${jdbc_url}"></property><property name="driverClassName" value="${jdbc_driver}"></property></bean><!--配置JDBCTemplate对象,并向里面注入DataSource--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--通过set方法注入连接池--><property name="dataSource" ref="dataSource"></property></bean><!--配置一个事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--将数据源注入事务管理器--><property name="dataSource"  ref="dataSource"></property></bean><!--配置通知--><tx:advice id="txAdvice"><!--配置事务参数--><tx:attributes><tx:method name="transMoney" isolation="DEFAULT" propagation="REQUIRED"/></tx:attributes></tx:advice><!--配置AOP--><aop:config><!--配置切入点--><aop:pointcut id="pt" expression="execution(* com.msb.service.AccountService.transMoney(..))"/><!--配置切面--><aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor></aop:config>
</beans>

创建零配置文件事务(配置类配置)

package com.msb.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;@Configuration  // 配置类标志注解
@ComponentScan(basePackages = "com.msb") // spring包扫描
@PropertySource("classpath:jdbc.properties") // 读取属性配置文件
@EnableTransactionManagement // 开启事务注解
public class SpringConfig {@Value("${jdbc_driver}")private String driver;@Value("${jdbc_url}")private String url;@Value("${jdbc_username}")private String username;@Value("${jdbc_password}")private String password;/*创建数据库连接池*/@Beanpublic DruidDataSource getDruidDataSource(){DruidDataSource dataSource=new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}no/*创建JdbcTemplate对象*/@Beanpublic JdbcTemplate getJdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate=new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}/*创建事务管理器*/@Beanpublic PlatformTransactionManager getPlatformTransactionManager(DataSource dataSource){DataSourceTransactionManager transactionManager =new DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;}
}

测试代码

    @Test()public void testTransaction3(){ApplicationContext context =new AnnotationConfigApplicationContext(SpringConfig.class);AccountService accountService = context.getBean(AccountService.class);int rows = accountService.transMoney(1, 2, 100);System.out.println(rows);}

附Spring测试组件

spring5框架自带了通用的日志封装,也可以整合自己的日志
1)spring移除了 LOG4jConfigListener,官方建议使用log4j2
2)spring5整合log4j2
导入log4j2依赖

        <!--log4j2 依赖--><!--<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.14.0</version></dependency>--><!--slf4-impl 包含了log4j2 依赖 引入它即可--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.14.0</version><scope>test</scope></dependency>

在resources目录下准备log4j2.xml的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" /></Console></Appenders><Loggers><Root level="debug"><AppenderRef ref="Console" /></Root></Loggers>
</Configuration>

spring5关于测试工具的支持

整合junit4
依赖的jar

        <!--Junit4单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>test</scope></dependency><!--spring test测试支持包--><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.5</version><scope>test</scope></dependency>

测试代码编写方式

//省略了加载容器配置文件代码编写

package com.msb.test;
import com.msb.config.SpringConfig;
import com.msb.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)// 指定测试支持类
@ContextConfiguration("classpath:applicationContext.xml")// 指定核心配置文件位置
public class Test2 {@Autowired // 注入要获取的beanprivate  AccountService accountService;@Test()public void testTransaction(){int rows = accountService.transMoney(1, 2, 100);System.out.println(rows);}
}

整合junit5

依赖的jar

 <!--junit5单元测试--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.7.0</version><scope>test</scope></dependency>

测试代码编写方式

package com.msb.test;
import com.msb.service.AccountService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;/*使用ExtentWith和ContextConfiguration注解*/
/*@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:applicationContext.xml")*/
// 使用复合注解代替前两个注解
@SpringJUnitConfig(locations = "classpath:applicationContext.xml")
public class Test3 {@Autowired // 注入要获取的beanprivate  AccountService accountService;@Testpublic void testTransaction(){int rows = accountService.transMoney(1, 2, 100);System.out.println(rows);}
}

相关文章:

Spring JdbcTemplate 和 事务

JdbcTemplate概述 JdbcTemplate是spring框架中提供的一个对象&#xff0c;是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如&#xff1a;操作关系型数据的JdbcTemplate和&#xff0c;操作nosql数据库的RedisTemplate&#xff0c;操作消息…...

C/C++:程序环境和预处理/宏

程序的翻译环境和执行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。第2种是执行环境&#xff0c;它用于实际执行代码。 编译和链接 一份源代码(比如test.c)需要通过编译&#xf…...

什么是死锁?死锁产生的四个必要条件是啥?如何避免和预防死锁的产生?

点个关注&#xff0c;必回关 文章目录什么是死锁死锁产生的原因&#xff1a;1、系统资源的竞争2、进程运行推进顺序不当引起死锁产生死锁的四个必要条件&#xff1a;死锁的避免与预防什么是死锁 死锁是指两个或两个以上的线程在执行过程中&#xff0c;由于竞争资源或者由于彼此…...

工程管理系统源码-物料管理-工程项目管理系统-建筑施工管理软件

如今建筑行业竞争激烈&#xff0c;内卷严重&#xff0c;发展趋势呈现两极分化&#xff0c;中小微企业的生存空间被逐步压缩&#xff0c;利润逐年减少。事实证明&#xff0c;工地上粗放式的人管人管理模式已经落于时代&#xff0c;劳动力纠纷和物料浪费现象尤其普遍&#xff0c;…...

Roboguide与TIA V16通讯

软件需求:1. roboguide;2. TIA V16;3. KEPServer; 在之前的文章中介绍过KEPServer与TIA V16的通讯,此处不再介绍。接下来,介绍roboguide与KEPServer的仿真通讯。 创建一个roboguide项目。选择【外部设备】➡【添加外部设备】 选择【OPC Server】➡【OK】 OPC服务器名称命…...

利用PyTorch深度学习框架进行多元回归

目录前言数据加载数据转换模型定义模型训练模型评估模型保存与加载完整代码讨论参考文献前言 大多数数据科学家以往经常常是利用传统的机器学习框架sklearn搭建多元回归模型&#xff0c;随着深度学习和强化学习越来越普及&#xff0c;很多数据科学家尝试使用深度学习框架来进行…...

EBS常用接口开发

整理了一些工作中常用的Oracle EBS接口和API&#xff0c;最早是看着大神黄建华文档起来的&#xff0c;格式内容参考他的文档&#xff0c;加上一些自己开发的程序和经历而已。 PO PO接收、检验、入库、退货-InterfaceAPI_刘文钊1的博客-CSDN博客 基础数据 EBS物料、bom、工艺导入…...

【完整】UR机械臂逆运动学求解过程及c++代码实现

有任何问题请在评论区留言&#xff0c;我尽可能的回复大家 一. 逆运动学的求解需要以下数学运算 利用DH参数得到每个关节的变换矩阵&#xff1b;利用变换矩阵求出机械臂整个链的变换矩阵&#xff1b;求出末端位姿&#xff1b;利用已知末端位姿和整个链的变换矩阵&#xff0c;…...

68. Python的相对路径

68. Python的相对路径 文章目录68. Python的相对路径1. 知识回顾2. 什么是相对路径3. 相对路径的语法4. 查看相对路径的方法5. 写出所有txt文件的相对路径5.1 同目录5.2 上级目录6. 用相对路径读取txt文件6.1 读取旅游.txt6.2 读取旅游经费.txt6.3 读取笔记.txt和new.txt6.4 读…...

java数据类型

数据类型 类型分类&#xff0c;存储范围&#xff0c;字面量&#xff0c;默认值&#xff0c;类型转换 类型分类 存储范围 数据类型字节数表示范围byte1-128~127short2-32768~32767&#xff0c;正负3万左右int4-2147483648~2147483647&#xff0c;正负21亿左右long8-922337203…...

Kotlin 替换非空断言的几种方式

Kotlin 出现断言的两种情形 IDE java 与 kotlin 自动转换时&#xff0c;自动添加非空断言的代码Smart Cast 失效 代码展示&#xff1a; class JavaConvertExample {private var name: String? nullfun init() {name ""}fun foo() {name null;}fun test() {if (…...

2023年了,来试试前端格式化工具

在大前端时代&#xff0c;前端的各种工具链穷出不断&#xff0c;有eslint, prettier, husky, commitlint 等, 东西太多有的时候也是trouble&#x1f602;&#x1f602;&#x1f602;,怎么正确的使用这个是每一个前端开发者都需要掌握的内容&#xff0c;请上车&#x1f697;&…...

spring cloud 企业工程项目管理系统源码+项目模块功能清单

工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和查看用户角色 4、菜单管理&#xff1a;实现对系统菜单的增删改查操…...

TCP分片解析

本文目录什么是IP分片为什么会产生IP分片为什么要避免IP分片如何避免IP分片什么是IP分片 IP协议栈将TCP/UDP传输层要求它发送的&#xff0c;但长度大于发送端口MTU的一个数据包&#xff0c;分割成多个IP报文后分多次发送。这些分成多次发送的多个IP报文就是IP分片。 为什么会…...

开发了一款基于 Flask 框架的在线电影网站系统(附 Python 源码)

文章目录前言项目介绍源码获取运行环境安装依赖库项目截图首页展示图视频展示页视频播放页后台管理页整体架构设计图项目目录结构图前台功能模块图后台功能模块图本地运行图前言 今天我给大家分享的是基于 Python 的 Flask 框架开发的在线电影网站系统&#xff0c;大家平时需要…...

如何获得CSM--敏捷教练证书

1、什么是CSM&#xff1f;CSM即Certified Scrum Master,Scrum Master负责确保所有人都能正确地理解并实施Scrum&#xff0c;确保Scrum团队遵循Scrum的理论、实践和规则。Scrum Master是Scrum团队中的服务型领导&#xff0c;帮助Scrum团队外的人员了解他们如何与Scrum团队交互是…...

Java面试数据库

目录 一、关系型数据库 数据库权限 表设计及创建 表数据相关 数据库架构优化 二、非关系型数据库 redis 今天给大家稍微整理了一下&#xff0c;内容有数据表设计的三大范式原则、sql查询如何优化、redis数据的击穿、穿透、雪崩等...&#xff0c;以及相关的面试题&#xff0…...

关于进行vue-cli过程中的解决错误的问题

好久没发文章了&#xff0c;直到今天终于开始更新了&#xff0c;最近想进军全端&#xff0c;准备学习下vue&#xff0c;但是这东西真的太难了&#xff0c;我用了一天的时间来解决在配置中遇到的问题&#xff01;主要问题&#xff1a;cnpm文件夹和vue-cli文件夹的位置不对并且vu…...

Rockchip Linux USB Gadget

一:概述 USB Gadget 是运行在 USB Peripheral 上配置 USB 功能的子系统,正常可被枚举的 USB 设备至少有 3 层逻辑层,有些功能还会在用户空间多跑一层逻辑代码。Gadget API 就是具体功能和硬件底层交互的中间层。从上到下,逻辑层分布为: USB Controller: USB上最底层的软…...

Linux -文件系统操作与帮助命令

1、Linux -文件系统操作 df — 查看磁盘的容量 df -h —以人类可以看懂的方式显示磁盘的容量&#xff0c;易读 du 命令查看目录的容量 # 默认同样以块的大小展示 du # 加上 -h 参数&#xff0c;以更易读的方式展示 du -h-d 参数指定查看目录的深度&#xff1a; # 只查看 1…...

UMI 创建react目录介绍及配置

UMI 生成react项目目录介绍及配置 react项目目录介绍umi多种配置方案运行时配置app.ts 的使用 1、umi创建的项目目录大致如下 ├─package.json 配置依赖以及启动打包所需的命令 ├─.umirc.ts 配置文件&#xff0c;包含 umi 内置功能和插件的配置 ├── dist 打包后生成的…...

基于matlab使用机器学习和深度学习进行雷达目标分类

一、前言此示例展示了如何使用机器学习和深度学习方法对雷达回波进行分类。机器学习方法使用小波散射特征提取与支持向量机相结合。此外&#xff0c;还说明了两种深度学习方法&#xff1a;使用SqueezeNet的迁移学习和长短期记忆&#xff08;LSTM&#xff09;递归神经网络。请注…...

Protocol Buffers V3语法全解

目录protobuf介绍protobuf使用protoc命令语法定义消息类型指定字段类型分配字段编号指定字段规则添加更多消息类型注释保留字段从.proto文件生成了什么&#xff1f;值类型默认值枚举使用其他消息类型导入定义嵌套类型更新消息类型未知字段any任意类型oneofoneof 特性兼容性问题…...

MediaPipe之人体关键点检测>>>BlazePose论文精度

BlazePose: On-device Real-time Body Pose tracking BlazePose&#xff1a;设备上实时人体姿态跟踪 论文地址&#xff1a;[2006.10204] BlazePose: On-device Real-time Body Pose tracking (arxiv.org) 主要贡献: &#xff08;1&#xff09;提出一个新颖的身体姿态跟踪解决…...

CSS从入门到精通专栏简介

先让我们来欣赏几个精美的网站&#xff1a; Matt Brett - Freelance Web Designer and WordPress Expert ‎2022 Year in Review • Letterboxd NIO蔚来汽车官方网站 小米官网 Silk – Interactive Generative Art 大屏数据可视化 你是否也有过这样的“烦恼”&#xff1a; * …...

day01常用DOS命令

day01课堂笔记&#xff08;第一章 Java开发环境的搭建&#xff09; 1、常用的DOS命令 1.1、怎么打开DOS命令窗口 win键 r &#xff08;组合键&#xff09;&#xff1a;可以打开“运行”窗口 在运行窗口文本框中输入: cmd 然后回车 1.2、什么是DOS命令呢&#xff1f; 在DOS命令…...

Java设计模式-生成器模式(建造模式)

1.1定义 维基百科定义 生成器模式&#xff08;英&#xff1a;Builder Pattern&#xff09;是一种设计模式&#xff0c;又名&#xff1a;建造模式&#xff0c;是一种对象构建模式。 它可以将复杂对象的建造过程抽象出来&#xff08;抽象类别&#xff09;&#xff0c;使这个抽象…...

ansible的常用模块介绍

ansible 常用命令/usr/bin/ansible  #Ansibe AD-Hoc 临时命令执行工具&#xff0c;常用于临时命令的执行/usr/bin/ansible-doc #Ansible 模块功能查看工具/usr/bin/ansible-galaxy  #下载/上传优秀代码或Roles模块 的官网平台&#xff0c;基于网络的/usr/bin/ansible-playbo…...

你不会还不知道如何监测用户的网络是否在线吧?

我最近遇到一个需求&#xff0c;要给网站添加一个用户网络离线提醒。要求我们要实时监测用户的网络状态&#xff0c;当用户断网了&#xff0c;我们要立马给用户弹出一个断网提醒。 那你可能会问&#xff0c;为什么要做这么一个需求呢&#xff1f;用户断网了&#xff0c;网页不…...

ASM Quorum FailGroup RAC on Extended Distance Clusters

法定容错组&#xff0c;和它失去联系也不影响集群运行 参考&#xff1a; How to Manually Add NFS voting disk to an Extended Cluster using ASM in 11.2 (Doc ID 1421588.1) Mount Options for Oracle files when used with NFS on NAS devices (Doc ID 359515.1) RAC: Fre…...

搜索引擎入口官网/关键词优化报价

项目中使用了tomcat&#xff0c;Nginx&#xff0c;测试阶段&#xff0c;生产阶段经常会有些bug需要调查。 需要有些日志管理工具&#xff0c;在没有ELK的情况下&#xff0c;可以通过配置nginx来实现基本的日常查看。不需要登录到Linux服务器上&#xff0c;通过浏览器即可快速获…...

巴音郭楞网站建设/怎么建个人网站

在分类中&#xff0c;和自己的父类关联public class AssessQualityIndex extends IdEntity<AssessQualityIndex> {private static final long serialVersionUID 1L; private String scoreStandard; // 评分标准private AssessQualityIndex parent; // 父级Js…...

网站做301跳转的方法/免费推客推广平台

今天&#xff0c;小编就据目前互联网行业的发展&#xff0c;以及大数据Hadoop分布式集群等等来讲解一下&#xff0c;政企如何搭建大数据计算服务平台。互联网信息技术的迅猛发展&#xff0c;云计算、物联网、智能科技、AI、超级计算机等等的出现和发展&#xff0c;使数据量不断…...

做网站用什么云服务器吗/营销活动有哪些

文章目录简介均值滤波实现Sobel边缘检测实现福利简介 FPGA数字图像处理系列终于迎来了第三更了&#xff0c;马上要开始写毕业论文了&#xff0c;这次的教程写的比较潦草&#xff0c;不过代码和上位机都是完整的&#xff0c;重点参考了《基于FPGA的数字图像处理原理及应用》的第…...

如何做传奇私服网站/seo搜索优化排名

题目链接&#xff1a;https://loj.ac/problem/10013 分析&#xff1a; 对于题目中给定的二次函数是符合用三分求极值的&#xff0c;关键是如何在n个这样的函数中找到最大的那一个&#xff1f; 我们会的就是一个这样的函数在给定区间内求极值。 所以&#xff0c;在每次三分的过…...

减肥产品网站模板/百度的电话人工客服电话

穆僮电脑小课堂 (QQ群&#xff1a;141826908)摘编整理如果你不小心把ubuntu引导弄坏了&#xff0c;比如重装了windows&#xff0c;比如格式化错了盘等等&#xff0c;那么通过下述方法可以简单的修复ubuntu首先&#xff0c;插入ubuntu的安装盘&#xff0c;没有的话只好做一个了&…...