spring 事务之@transactional的使用与回滚

一、事务简单介绍
事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。

1.1 事务基本要素
    原子性(Atomicity): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
    一致性(Consistency): 事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
    隔离性(Isolation): 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
    持久性(Durability): 事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

1.2 Spring事务属性
Spring事务属性包含了5个方面:传播行为、隔离规则、回滚规则、事务超时、是否只读。

1.2.1 传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。Spring定义了七种传播行为:

传播行为含义
TransactionDefinition.PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务,则加入到这个事务中。这是最常见的选择。
TransactionDefinition.PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
TransactionDefinition.PROPAGATION_MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
TransactionDefinition.PROPAGATION_REQUIRED_NEW表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中。如果当前存在事务,就把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
TransactionDefinition.PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

1.2.2 隔离规则
隔离级别定义了一个事务可能受其他并发事务影响的程度。 在实际开发过程中,我们绝大部分的事务都是有并发情况。下多个事务并发运行,经常会操作相同的数据来完成各自的任务。在这种情况下可能会导致以下的问题:
    脏读(Dirty reads)—— 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
    不可重复读(Nonrepeatable read)—— 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
    幻读(Phantom read)—— 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
    不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
    咱们已经知道了在并发状态下可能产生: 脏读、不可重复读、幻读的情况。因此我们需要将事务与事务之间隔离。根据隔离的方式来避免事务并发状态下脏读、不可重复读、幻读的产生。Spring中定义了五种隔离规则:

隔离级别含义脏读不可重复读幻读
TransactionDefinition.ISOLATION_DEFAULT使用后端数据库默认的隔离级别
TransactionDefinition.ISOLATION_READ_UNCOMMITTED允许读取尚未提交的数据变更(最低的隔离级别)
TransactionDefinition.ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据
TransactionDefinition.ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改
TransactionDefinition.ISOLATION_SERIALIZABLE最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

ISOLATION_SERIALIZABLE 隔离规则类型在开发中很少用到。举个很简单的例子。咱们使用了ISOLATION_SERIALIZABLE规则。A,B两个事务操作同一个数据表并发过来了。A先执行。A事务这个时候会把表给锁住,B事务执行的时候直接报错。

补充:

事务隔离级别为ISOLATION_READ_UNCOMMITTED时,写数据只会锁住相应的行。
事务隔离级别为可ISOLATION_REPEATABLE_READ时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
事务隔离级别为ISOLATION_SERIALIZABLE时,读写数据都会锁住整张表。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也就越大。

1.2.3 回滚规则
    事务回滚规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,只有未检查异常(RuntimeException和Error类型的异常)会导致事务回滚。而在遇到检查型异常时不会回滚。 但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

1.2.4 事务超时
    为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,也会占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。

1.2.5 是否只读
    如果在一个事务中所有关于数据库的操作都是只读的,也就是说,这些操作只读取数据库中的数据,而并不更新数据, 这个时候我们应该给该事务设置只读属性,这样可以帮助数据库引擎优化事务。提升效率。

二、@Transactional使用
Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式:

    编程式事务:允许用户在代码中精确定义事务的边界。编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

    声明式事务: 基于AOP,有助于用户将操作与事务规则进行解耦。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务管理也有两种常用的方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于@Transactional注解的方式。显然基于注解的方式更简单易用,更清爽。@Transactional注解的使用也是我们本文着重要理解的部分。

    显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

2.1 @Transactional介绍
@Transactional注解 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然@Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring
建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional注解应该只被应用到
public 方法上,这是由Spring AOP的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用
@Transactional 注解,这将被忽略,也不会抛出任何异常。
默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

2.2 @Transactional注解属性
@Transactional注解里面的各个属性和咱们在上面讲的事务属性里面是一一对应的。用来设置事务的传播行为、隔离规则、回滚规则、事务超时、是否只读。

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {/*** 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。*/@AliasFor("transactionManager")String value() default "";/*** 同上。*/@AliasFor("value")String transactionManager() default "";/*** 事务的传播行为,默认值为 REQUIRED。*/Propagation propagation() default Propagation.REQUIRED;/*** 事务的隔离规则,默认值采用 DEFAULT。*/Isolation isolation() default Isolation.DEFAULT;/*** 事务超时时间。*/int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;/*** 是否只读事务*/boolean readOnly() default false;/*** 用于指定能够触发事务回滚的异常类型。*/Class<? extends Throwable>[] rollbackFor() default {};/*** 同上,指定类名。*/String[] rollbackForClassName() default {};/*** 用于指定不会触发事务回滚的异常类型*/Class<? extends Throwable>[] noRollbackFor() default {};/*** 同上,指定类名*/String[] noRollbackForClassName() default {};}

2.2.1 value、transactionManager属性
    它们两个是一样的意思。当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。大多数项目只需要一个事务管理器。然而,有些项目为了提高效率、或者有多个完全不同又不相干的数据源,从而使用了多个事务管理器。机智的Spring的Transactional管理已经考虑到了这一点,首先定义多个transactional manager,并为qualifier属性指定不同的值;然后在需要使用@Transactional注解的时候指定TransactionManager的qualifier属性值或者直接使用bean名称。配置和代码使用的例子:

<tx:annotation-driven/><bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="datasource1"></property><qualifier value="datasource1Tx"/>
</bean><bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="datasource2"></property><qualifier value="datasource2Tx"/>
</bean>
public class TransactionalService {@Transactional("datasource1Tx")public void setSomethingInDatasource1() { ... }@Transactional("datasource2Tx")public void doSomethingInDatasource2() { ... }}

2.2.2 propagation属性
    propagation用于指定事务的传播行为,默认值为 REQUIRED。propagation有七种类型,就是我们在上文中讲到的事务属性传播行为的七种方式,如下所示:

propagation属性事务属性-传播行为含义
REQUIREDTransactionDefinition.PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务,则加入到这个事务中。这是最常见的选择。
SUPPORTSTransactionDefinition.PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORYTransactionDefinition.PROPAGATION_MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常。
REQUIRES_NEWTransactionDefinition.PROPAGATION_REQUIRES_NEW表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。
NOT_SUPPORTEDTransactionDefinition.PROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中。如果当前存在事务,就把当前事务挂起。
NEVERTransactionDefinition.PROPAGATION_NEVER表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常。
NESTEDTransactionDefinition.PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

2.2.3 isolation属性
    isolation用于指定事务的隔离规则,默认值为DEFAULT。@Transactional的隔离规则和上文事务属性里面的隔离规则也是一一对应的。总共五种隔离规则,如下所示:

@isolation属性事务属性-隔离规则含义脏读不可重复读幻读
DEFAULTTransactionDefinition.ISOLATION_DEFAULT使用后端数据库默认的隔离级别
READ_UNCOMMITTEDTransactionDefinition.ISOLATION_READ_UNCOMMITTED允许读取尚未提交的数据变更(最低的隔离级别)
READ_COMMITTEDTransactionDefinition.ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据
REPEATABLE_READTransactionDefinition.ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改否 否
SERIALIZABLETransactionDefinition.ISOLATION_SERIALIZABLE最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的

2.2.4 timeout
    timeout用于设置事务的超时属性。

2.2.5 readOnly
    readOnly用于设置事务是否只读属性。

2.2.6 rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName
    rollbackFor、rollbackForClassName用于设置那些异常需要回滚; noRollbackFor、noRollbackForClassName用于设置那些异常不需要回滚。他们就是在设置事务的回滚规则。

注意:

1、Transactional 默认在error和runtimeException运行时异常会进行回滚,非运行时异常不会回滚。 运行时异常:空指针异常,类型转换异常等;非运行时异常:io异常,sql异常等。
2、 @Transactional(rollbackFor
= Exception.class)使所有异常抛出时都会回滚,另需注意:使用try-catch{}时,如果不用throw抛出异常时transactional不会生效,只有使用try-catch{throw
new exception}抛出异常时,transactional才会生效,会进行回滚。

2.3 @Transactional注解的使用
    @Transactional注解的使用关键点在理解@Transactional注解里面各个参数的含义。这个咱们在上面已经对@Transactional注解参数的各个含义做了一个简单的介绍。接下来,咱们着重讲一讲@Transactional注解使用过程中一些注意的点。

@Transactional注解内部实现依赖于Spring
AOP编程。而AOP在默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为。

2.3.1 @Transactional 注解尽量直接加在方法上
    为什么:因为@Transactional直接加在类或者接口上,@Transactional注解会对类或者接口里面所有的public方法都有效(相当于所有的public方法都加上了@Transactional注解,而且注解带的参数都是一样的)。第一影响性能,可能有些方法我不需要@Transactional注解,第二方法不同可能@Transactional注解需要配置的参数也不同,比如有一个方法只是做查询操作,那咱们可能需要配置Transactional注解的readOnly参数。所以强烈建议@Transactional注解直接添加的需要的方法上。

2.3.2 @Transactional 注解必须添加在public方法上,private、protected方法上是无效的
    在使用@Transactional 的时候一定要记住,在private,protected方法上添加@Transactional 注解不会有任何效果。相当于没加一样。即使外部能调到protected的方法也无效。和没有添加@Transactional一样。

2.3.3 函数之间相互调用
    关于有@Transactional的函数之间调用,会产生什么情况。这里咱们通过几个例子来说明。

2.3.3.1 同一个类中函数相互调用
    同一个类AClass中,有两个函数aFunction、aInnerFunction。aFunction调用aInnerFunction。而且aFunction函数会被外部调用。

情况0: aFunction添加了@Transactional注解,aInnerFunction函数没有添加。aInnerFunction抛异常。

public class AClass {@Transactional(rollbackFor = Exception.class)public void aFunction() {//todo: 数据库操作A(增,删,该)aInnerFunction(); // 调用内部没有添加@Transactional注解的函数}private void aInnerFunction() {//todo: 操作数据B(做了增,删,改 操作)throw new RuntimeException("函数执行有异常!");}}

结果:两个函数操作的数据都会回滚。

情况1:两个函数都添加了@Transactional注解。aInnerFunction抛异常。

public class AClass {@Transactional(rollbackFor = Exception.class)public void aFunction() {//todo: 数据库操作A(增,删,该)aInnerFunction(); // 调用内部没有添加@Transactional注解的函数}@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)private void aInnerFunction() {//todo: 操作数据B(做了增,删,改 操作)throw new RuntimeException("函数执行有异常!");}}

结果:同第一种情况一样,两个函数对数据库操作都会回滚。因为同一个类中函数相互调用的时候,内部函数添加@Transactional注解无效。@Transactional注解只有外部调用才有效。

情况2: aFunction不添加注解,aInnerFunction添加注解。aInnerFunction抛异常。

public class AClass {public void aFunction() {//todo: 数据库操作A(增,删,该)aInnerFunction(); // 调用内部没有添加@Transactional注解的函数}@Transactional(rollbackFor = Exception.class)protected void aInnerFunction() {//todo: 操作数据B(做了增,删,改 操作)throw new RuntimeException("函数执行有异常!");}}

结果:两个函数对数据库的操作都不会回滚。因为内部函数@Transactional注解添加和没添加一样。

情况3:aFunction添加了@Transactional注解,aInnerFunction函数没有添加。aInnerFunction抛异常,不过在aFunction里面把异常抓出来了。

public class AClass {@Transactional(rollbackFor = Exception.class)public void aFunction() {//todo: 数据库操作A(增,删,该)try {aInnerFunction(); // 调用内部没有添加@Transactional注解的函数} catch (Exception e) {e.printStackTrace();}}private void aInnerFunction() {//todo: 操作数据B(做了增,删,改 操作)throw new RuntimeException("函数执行有异常!");}}

结果:两个函数里面的数据库操作都成功。事务回滚的动作发生在当有@Transactional注解函数有对应异常抛出时才会回滚。(当然了要看你添加的@Transactional注解有没有效)。

2.3.3.1. 不同类中函数相互调用
    两个类AClass、BClass。AClass类有aFunction、BClass类有bFunction。AClass类aFunction调用BClass类bFunction。最终会在外部调用AClass类的aFunction。

情况0:aFunction添加注解,bFunction不添加注解。bFunction抛异常。

@Service()
public class AClass {private BClass bClass;@Autowiredpublic void setbClass(BClass bClass) {this.bClass = bClass;}@Transactional(rollbackFor = Exception.class)public void aFunction() {//todo: 数据库操作A(增,删,该)bClass.bFunction();}}@Service()
public class BClass {public void bFunction() {//todo: 数据库操作A(增,删,该)throw new RuntimeException("函数执行有异常!");}
}

结果:两个函数对数据库的操作都回滚了。

情况1:aFunction、bFunction两个函数都添加注解,bFunction抛异常。

@Service()
public class AClass {private BClass bClass;@Autowiredpublic void setbClass(BClass bClass) {this.bClass = bClass;}@Transactional(rollbackFor = Exception.class)public void aFunction() {//todo: 数据库操作A(增,删,该)bClass.bFunction();}}@Service()
public class BClass {@Transactional(rollbackFor = Exception.class)public void bFunction() {//todo: 数据库操作A(增,删,该)throw new RuntimeException("函数执行有异常!");}
}

结果:两个函数对数据库的操作都回滚了。两个函数里面用的还是同一个事务。这种情况下,你可以认为事务rollback了两次。两个函数都有异常。

情况2:aFunction、bFunction两个函数都添加注解,bFunction抛异常。aFunction抓出异常。

@Service()
public class AClass {private BClass bClass;@Autowiredpublic void setbClass(BClass bClass) {this.bClass = bClass;}@Transactional(rollbackFor = Exception.class)public void aFunction() {//todo: 数据库操作A(增,删,该)try {bClass.bFunction();} catch (Exception e) {e.printStackTrace();}}}@Service()
public class BClass {@Transactional(rollbackFor = Exception.class)public void bFunction() {//todo: 数据库操作A(增,删,该)throw new RuntimeException("函数执行有异常!");}
}

结果:两个函数数据库操作都没成功。而且还抛异常了。org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only。看打印出来的解释也很好理解把。咱们也可以这么理解,两个函数用的是同一个事务。bFunction函数抛了异常,调了事务的rollback函数。事务被标记了只能rollback了。程序继续执行,aFunction函数里面把异常给抓出来了,这个时候aFunction函数没有抛出异常,既然你没有异常那事务就需要提交,会调事务的commit函数。而之前已经标记了事务只能rollback-only(以为是同一个事务)。直接就抛异常了,不让调了。

情况3:aFunction、bFunction两个函数都添加注解,bFunction抛异常。aFunction抓出异常。这里要注意bFunction函数@Transactional注解我们是有变化的,加了一个参数propagation = Propagation.REQUIRES_NEW,控制事务的传播行为。表明是一个新的事务。其实咱们情况3就是来解决情况2的问题的。

@Service()
public class AClass {private BClass bClass;@Autowiredpublic void setbClass(BClass bClass) {this.bClass = bClass;}@Transactional(rollbackFor = Exception.class)public void aFunction() {//todo: 数据库操作A(增,删,该)try {bClass.bFunction();} catch (Exception e) {e.printStackTrace();}}}@Service()
public class BClass {@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)public void bFunction() {//todo: 数据库操作A(增,删,该)throw new RuntimeException("函数执行有异常!");}
}

结果:bFunction函数里面的操作回滚了,aFunction里面的操作成功了。有了前面情况2的理解。这种情况也很好解释。两个函数不是同一个事务了。

关于@Transactional注解的使用,就说这么些。最后做几点总结:

要知道@Transactional注解里面每个属性的含义。@Transactional注解属性就是来控制事务属性的。通过这些属性来生成事务。

要明确我们添加的@Transactional注解会不会起作用。@Transactional注解在外部调用的函数上才有效果,内部调用的函数添加无效,要切记。这是由AOP的特性决定的。

要明确事务的作用范围,有@Transactional的函数调用有@Transactional的函数的时候,进入第二个函数的时候是新的事务,还是沿用之前的事务。稍不注意就会抛UnexpectedRollbackException异常。

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

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

相关文章

python可视化图形界面_Python PyQt5 Designer 可视化图形界面模块

PYQT5 Designer简介强大的可视化GUI设计工具, 帮助我们快速开发PyQt.它生成UI界面为.ui文件, 通过命令将.ui转为.py文件.准备工作安装PyQt5: pip install pyqt5安装Qt工具: pip install pyqt5-tools(坑提示&#xff1a;一开始安装的pyqt5版本高了&#xff0c;结果安装QT工具的时…

雷克世界:Gyrfalcon加入芯片角斗场,又一款改变AI界的产品问世

来源&#xff1a;雷克世界 概要&#xff1a;随着人工智能产业规模扩大&#xff0c;众多巨头和初创公司纷纷加入人工智能芯片领域。 随着人工智能产业规模扩大&#xff0c;众多巨头和初创公司纷纷加入人工智能芯片领域&#xff0c;今天来了解一家旨在开发低成本、低功耗、高性能…

Freemarker静态化页面的使用

Freemarker 是一种基于模板的&#xff0c;用来生成输出文本的通用工具&#xff0c;所以我们必须要定制符合自己业务的模板&#xff0c;然后生成自己的文本&#xff08;html页面&#xff0c;string字符串&#xff0c;xml文本等等&#xff09;。Freemarker是通过freemarker.templ…

SessionHelper

问题描述&#xff1a; strut2 的织入 Session 为原始 Map 类型&#xff0c;没有泛型化&#xff0c;在添加属性时就会有一个恼人的警告。 功能&#xff1a; 1、安全的消除警告 2、插入时检查类型&#xff0c;如果不符就提前报错&#xff08;免得取值时才报转换异常的错误&…

报告怎么看_体检报告怎么看? 超实用的阅读指南来了!

体检报告怎么看&#xff1f;超实用的阅读指南来了&#xff01;要点概括除了禁食禁水可以吞口水吗&#xff1f;这样的问题&#xff0c;还有胆固醇、甘油三酯、胆红素…这些指标都是什么意思&#xff1f;出现升高或降低提示了怎样的身体变化&#xff1f;九图带你读懂&#xff01;…

从基础设施的演变,看人工智能到底需要什么样的底层平台

来源&#xff1a;亿欧 概要&#xff1a;大数据、大容量存储、弹性计算和各类算法的发展&#xff0c;尤其是在深度学习领域的发展&#xff0c;带来了各类脑洞大开的创新应用。 机器学习和人工智能的时代已经到来。大数据、大容量存储、弹性计算和各类算法的发展&#xff0c;尤其…

前后台加解密的使用--SHA256算法 RSA算法 AES算法

SHA256算法 sha256与md5一样是散列算法&#xff0c;不是加密算法&#xff0c;不存在解密的问题&#xff0c;因此是不可逆的&#xff0c;可以通过keypassword&#xff0c;对密码进行加密&#xff0c;在后台进行比对&#xff0c;安全性比md5高一点&#xff0c;加密后生成的密文为…

性能测量工具类——TimeMeasureUtil TimeMeasureProxy

TimeMeasureUtil&#xff1a;做单次时间测量。 1、为了能确保 startTime 和 endTime 都正确设置&#xff0c;因而采用实例对象来实现。每次测量是都能判断对象是否处在正确状态。 2、该类为工具类&#xff0c;即使测试时产生许多对象实例也对软件无任何影响。 public class T…

如何看屈曲因子_Abaqus 非线性屈曲分析方法

通常情况下&#xff0c;我们只用关注产品结构本身的强度和刚度满足一定的要求或标准即可。但实际工程中&#xff0c;对于像细长类的结构、薄壁结构&#xff0c;我们还得考虑它的稳定性问题&#xff0c;这也就是我们通常所说的失稳问题或者塌陷问题。在有限元分析中&#xff0c;…

人类首张脑电波连接全图问世

来源&#xff1a;科技日报 概要&#xff1a;美国宾夕法尼亚大学的神经学家根据300名接受神经外科手术患者大脑中30000个电极的数据&#xff0c;绘制出第一张脑电波连接全图。 美国国防部高级研究计划局&#xff08;DARPA&#xff09;资助的、与“恢复活跃记忆”相关的大脑研究项…

EasyMock 简介

来源&#xff1a;https://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/ 使用注意&#xff1a; a、静态方法&#xff08; static 修饰&#xff09;无法模拟。 1、使用 EasyMock 进行单元测试 通过 EasyMock&#xff0c;我们可以为指定的接口动态的创建 Mock 对…

login控件authenticate_asp.net Login控件基本属性及事件说明

当前位置:IT大杂烩>JavaScript> asp.net Login控件基本属性及事件说明asp.net Login控件基本属性及事件说明www.someabcd.com 网友分享于&#xff1a;Jun 8, 2018 9:43:39 AM原文:asp.net Login控件基本属性及事件说明 Login系列控件是微软为了简化我们的开发过程&#…

全球半导体产业迁移 中国的机遇与挑战

来源&#xff1a;36氪 概要&#xff1a;商务部24日发布公告说&#xff0c;以附加“限制性条件”的形式批准了日月光半导体收购矽品精密股权案。 商务部24日发布公告说&#xff0c;以附加“限制性条件”的形式批准了日月光半导体收购矽品精密股权案。这个附加的“限制性条件”&…

dts同步常见问题_阿里云DTS数据同步常见问题(一)

阿里云的数据同步工具DTS确实是一件非常不错的工具&#xff0c;可以实现不同数据源之间的数据迁移、数据同步&#xff0c;只需要配置好两端的数据源就可以自动实现&#xff0c;不在需要人为的操作&#xff0c;非常的方便。但是如果不熟悉DTS的话呢&#xff0c;会遇到各种各样的…

暂时

/*** 使HTML的标签失去作用* * param input* 被操作的字符串* return String*/public static final String escapeHTMLTag(String input) {if (input null) {input "";return input;}input input.trim().replaceAll("&", "&&qu…

mysql的程序怎么升级成mysqli_如何将mysql更改为mysqli?-问答-阿里云开发者社区-阿里云...

首先要做的可能是将每个mysql_函数调用都替换为等效函数mysqli_&#xff0c;至少在您愿意使用过程式API的情况下-考虑到您已经有一些基于MySQL API的代码&#xff0c;这将是更简单的方法是一种程序性的。为了解决这个问题&#xff0c;“ MySQLi扩展功能摘要”绝对是有用的。例如…

待完成任务列表

1、将 HT 控件全部对象化。 a、抽象出 print 方法 b、使用构建器模式控制参数&#xff1a;部分是必须在创建对象时给定&#xff0c;部分是可以给定也可以使用默认值。 2、开发——小助手&#xff0c;工具 a、要对“名称定义”、“单元测试”进行&#xff0c;添加&#xff0c;编…

mysql插入实现存在更新_mysql 记录不存在时插入 记录存在则更新的实现方法

mysql 记录不存在时插入在 MySQL 中&#xff0c;插入(insert)一条记录很简单&#xff0c;但是一些特殊应用&#xff0c;在插入记录前&#xff0c;需要检查这条记录是否已经存在&#xff0c;只有当记录不存在时才执行插入操作&#xff0c;本文介绍的就是这个问题的解决方案。问题…

阿里智能对话交互实践与创新

来源&#xff1a;人工智能头条 作者 &#xff1a;孙健&#xff0c;李永彬&#xff0c;陈海青&#xff0c;邱明辉 概要&#xff1a;过去 20 多年&#xff0c;互联网及移动互联网将人类带到了一个全新的时代&#xff0c;如果用一个词来总结和概括这个时代的话&#xff0c;「连接」…

HT 相关

设置系统语言——日语测试用 解决方案 按照以下说明将系统语言环境更改为您所需的语言&#xff1a; 更改 Windows XP、Vista 和 Windows 7 的系统位置 注&#xff1a;必须以具有管理权限的用户身份登录。 单击开始 > 控制面板。 Windows 7 和 Vista&#xff1a;依次单击…