1.Spring事务传播特性
Spring事务属性的种类:传播行为、隔离级别、只读和事务超时
1.传播行为定义了被调用方法的事务边界
传播行为 | 意义 |
---|---|
PROPERGATION_MANDATORY | 表示方法必须运行在一个事务中,如果当前事务不存在,就抛出异常 |
PROPAGATION_NESTED | 表示如果当前事务存在,则方法应该运行在一个嵌套事务中。否则,它看起来和 PROPAGATION_REQUIRED 看起来没什么俩样 |
PROPAGATION_NEVER | 表示方法不能运行在一个事务中,否则抛出异常 |
PROPAGATION_NOT_SUPPORTED | 表示方法不能运行在一个事务中,如果当前存在一个事务,则该方法将被挂起 |
PROPAGATION_REQUIRED | 表示当前方法必须运行在一个事务中,如果当前存在一个事务,那么该方法运行在这个事务中,否则,将创建一个新的事务 |
PROPAGATION_REQUIRES_NEW | 表示当前方法必须运行在自己的事务中,如果当前存在一个事务,那么这个事务将在该方法运行期间被挂起 |
PROPAGATION_SUPPORTS | 表示当前方法不需要运行在一个是事务中,但如果有一个事务已经存在,该方法也可以运行在这个事务中 |
2.隔离级别
在操作数据时可能带来 3 个副作用,分别是脏读、不可重复读、幻读。为了避免这 3 种副作用的发生,在标准的 SQL 语句中定义了 4 种隔离级别,分别是未提交读、已提交读、可重复读、可序列化。而在 Spring 事务中提供了 5 种隔离级别来对应在 SQL 中定义的 4 种隔离级别,如下:
隔离级别 | 意义 |
---|---|
ISOLATION_DEFAULT | 使用后端数据库默认的隔离级别 |
ISOLATION_READ_UNCOMMITTED | 允许读取未提交的数据(对应未提交读),可能导致脏读、不可重复读、幻读 |
ISOLATION_READ_COMMITTED | 允许在一个事务中读取另一个已经提交的事务中的数据(对应已提交读)。可以避免脏读,但是无法避免不可重复读和幻读 |
ISOLATION_REPEATABLE_READ | 一个事务不可能更新由另一个事务修改但尚未提交(回滚)的数据(对应可重复读)。可以避免脏读和不可重复读,但无法避免幻读 |
ISOLATION_SERIALIZABLE | 这种隔离级别是所有的事务都在一个执行队列中,依次顺序执行,而不是并行(对应可序列化)。可以避免脏读、不可重复读、幻读。但是这种隔离级别效率很低,因此,除非必须,否则不建议使用。 |
补充:
何为脏读、不可重复读、幻读。
(1) 脏读: 脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。这跟不可重复读类似,但是第二个事务不需要执行提交.
(2) 不可重复读: 在多版本并行控制机制中,当一个遇到提交冲突的事务需要回退但却被释放时,会发生不可重复读问题. 在基于锁的并行控制方法中,如果在执行select时不添加读锁,就会发生不可重复读问题.
不可重复读的重点是修改: 同样的条件, 你读取过的数据, 再次读取出来发现值不一样了.在一个事务中前后两次读取的结果并不致,导致了不可重复读.
(3) 幻读: 幻读发生在当两个完全相同的查询执行时,第二次查询所返回的结果集跟第一个查询不相同.幻读的重点在于新增或者删除 (数据条数变化)。同样的条件, 第1次和第2次读出来的记录数不一样
3 只读
如果在一个事务中所有关于数据库的操作都是只读的,也就是说,这些操作只读取数据库中的数据,而并不更新数据,那么应将事务设为只读模式( READ_ONLY_MARKER ) , 这样更有利于数据库进行优化 。
因为只读的优化措施是事务启动后由数据库实施的,因此,只有将那些具有可能启动新事务的传播行为 (PROPAGATION_NESTED 、 PROPAGATION_REQUIRED 、 PROPAGATION_REQUIRED_NEW) 的方法的事务标记成只读才有意义。
如果使用 Hibernate 作为持久化机制,那么将事务标记为只读后,会将 Hibernate 的 flush 模式设置为 FULSH_NEVER, 以告诉 Hibernate 避免和数据库之间进行不必要的同步,并将所有更新延迟到事务结束。
4. 事务超时
如果一个事务长时间运行,这时为了尽量避免浪费系统资源,应为这个事务设置一个有效时间,使其等待数秒后自动回滚。与设置“只读”属性一样,事务有效属性也需要给那些具有可能启动新事物的传播行为的方法的事务标记成只读才有意义。
2.java有虚函数吗?与C++有什么区别?
Java肯定是有虚函数的.
定义: 在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数.
用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};
实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。----------(百度百科)
测试:
package test;
class A{
public void FUN(){
System.out.println("FUN in A is called");
}
}
class B extends A{
public void FUN(){
System.out.println("FUN in B is called");
}
}
public class VirtualTest {
public static void main(String args[]) {
A a = new A();
B b = new B();
A p;
p = a;
p.FUN();
p = b;
p.FUN();
}
}
在上面的代码中,我们定义了一个基类指针(在java中应该叫引用)去指向不同的对象,可以发现同样可以实现多态。也就是说,java的普通成员函数(没有被static、native等关键字修饰)就是虚函数,原因很简单,它本身就实现虚函数实现的功能------多态。
补充:
C++ | JAVA |
---|---|
虚函数 | 普通函数 |
纯虚函数 | 抽象函数 |
抽象类 | 抽象类 |
虚基类 | 接口 |
结论:java类中普通成员函数就是虚函数。
其它详细解释,请参考: https://blog.csdn.net/wuqiuping695/article/details/49069779
3.IO流大全
4.List、list<?>、list<?extends>等区别
- List既是点也是范围,当表示范围时,表示最大范围
- 如果尖括号里的是一个类,那么尖括号里的就是一个点,比如
- 如果尖括号里面带有问号,那么代表一个范围,<? extends A> 代表小于等于A的范围,<? super A>代表大于等于A的范围,<?>代表全部范围
- 尖括号里的所有点之间互相赋值都是错,除非是俩相同的点
- 尖括号小范围赋值给大范围,对,大范围赋值给小范围,错。如果某点包含在某个范围里,那么可以赋值,否则,不能赋值
- List<?>和List 是相等的,都代表最大范围