有三种方式处理事务的模式 1. Client Own Transaction 应用场景: 服务端Service 组件不允许修改,且都是细粒度的服务,一次调用不能满足一个ACID的业务请求 由于客户端transaction context需要传播propagation到Server端,需要RMI协议支持。好像Spring中不支持。 通过RMI,EJB这种方式的话要求客户端用programmatic 事务处理,服务端需要用declarative 事务处理。这是因为transaction context不能在programmatic事务处理中传播。 缺点: 多次远程服务调用影响性能 方式: 统一由客户端发起,提交,rollback事务。 Server端组件事务读操作声明成support, 其他写操作需声明成Mandatory 2. Domain Service Own Transaction 应用场景: 服务端提供了粗粒度的服务封装 客户端不能管理事务,如Web Service Client(服务端封装成了Web Service) 减轻客户端的复杂度 方式: 事务只在这一层处理发起,提交,rollback Server端组件事务读操作声明成support, 其他写操作需声明成Required 3. Service Delegate Own Transaction 以上1和2的折中,相当于在Client和Server之间加入了一个Business Delegate层。 事务统一在这一层处理。 好处: 后端的Server层可以剥离Transaction相关的API,用POJO写 缺点: 客户端的逻辑(如一次请求多个服务端的调用)需要移到这一层,可能依赖于UI层的框架API,如HttpServletRequest之类的 方式: 该层方法事务读操作声明成support, 其他写操作需声明成Required
override 覆写 用于实例方法,签名相同,动态分派 a) 子类方法限定要大于等于父类。即限定变大了。 b) Never add exception types to the throws clause of a method overridden in a subclass 也即不能添加更多的异常到子类签名中。可以是父类异常的子类异常,甚至不加异常。所以异常应该是变小了。这主要是为了遵守Liskov OOP 替换原则。子类必须能替换父类,如果子类里有新加的异常,Try/Catch起码要引起变动。相反,子类没有异常并不影响现有的代码。 2. Hide 隐藏 子类属性隐藏父类的,也即父类属性不能继承到子类中(相同名字的话,可以是不同类型)。当然可以通过把子类转型到父类访问父类的属性。这是与覆写不同的地方。 a) private 属性根据dynamic type决定 frendly,pretected,public 属性根据static type 决定 静态属性根据类名决定,与类实例无关(即使是static final 类型的子类亦可Hide) 3. overload 重载 父类frendly / pretected / public 方法会继承到子类中,这时父类和子类中相同的方法签名也是overload(重载)。并不是只有定义在一个类中的方法才构成重载。 注意重载哪个方法是在编译时选择的,这与Override非常不同。 4. shadow 遮蔽 变量,方法或类型都有可能 常见的是临时变量遮蔽了类变量或者全局变量。对象方法遮蔽了static import进来的方法。 外围类(enclosing class)包含一个内部类(inner class),内部类(比如继承Thread类)继承的成员方法(比如sleep)遮蔽了外围累(enclosing class)的方法。 5. obscure 遮掩 变量可以遮掩类型,类型可以遮掩包。也即优先级不一样 比如声明一个变量名字为System(非正规的命名),该变量System会obscure Java系统类型System
实现多线程: 1. extends Thread 2. implement Runnable interface 线程应该用start 方法来启动。直接运行Run 方法并没有启动多线程,还是在主线程中执行run方法,跟普通方法调用一样。 3. 一般倾向于用new Thread(Runnable)这种方式而不是继承Thread,理由有二: 1. 用Runnable接口可以留下多继承的余地 2. 不会因为Thread类继承下来的锁或者方法相互干扰 sleep() join(),相当与thread实例.wait,会释放thread实例对应的锁。对于锁应该声明一个私有的对象锁,这样不会暴露到外面去引起误用。 private final Object lock = new Object(); 误用的例子如下: 比如创建一个新的Thread实例,系统都会获取Thread类上的锁。以下代码会阻止新线程的创建。 synchronized(Thread.class){ Thread.sleep(Long.MAX_VALUE); } 4. Synchronized 方法的锁是针对不同线程的,不同线程只能顺序执行该同步方法。但是同一个线程可以重复地获得某个相同的锁。也即可以调用别的Synchronized 方法,只要用的是同一把锁。
2. Spring Framework 支持的事务属性 1) PROPAGATION_REQUIRED --支持当前的事务,如果不存在就创建一个新的。这是最常用的选择。 2) PROPAGATION_SUPPORTS --支持当前的事务,如果不存在就不使用事务。 3) PROPAGATION_MANDATORY --支持当前的事务,如果不存在就抛出异常。 4)PROPAGATION_REQUIRES_NEW --创建一个新的事务,并暂停当前的事务(如果存在)。 5) PROPAGATION_NOT_SUPPORTED --不使用事务,并暂停当前的事务(如果存在)。 6) PROPAGATION_NEVER --不使用事务,如果当前存在事务就抛出异常。 7) PROPAGATION_NESTED --如果当前存在事务就作为嵌入事务执行,否则与PROPAGATION_REQUIRED类似。 3. 注意事项 1)PROPAGATION_REQUIRES_NEW 与 PROPAGATION_NESTED PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行. 另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交. Savepoint需要最新的JDBC规范来支持。JDBC3? 由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back. 2)Required和mandatory事务属性 一般写操作配置成这两种事务。 两种都支持transaction context. 区别在如果调用时没有transaction context, Required的会发起一个新的事务。而mandatory的会抛出异常。 深层次的区别基于下面的规则: With the exception of the stateful session bean, the method that starts a transaction must be the same method that terminates the transaction. 因为Required不能确认事务是否是在此方法中启动的还是从外面传进来的,因此不知道是否该做rollback这种处理当出现异常时。而Mandatory确认事务都是从外面传入的,因此知道自己不需要处理这种逻辑。 也就是说,如果事务不是在该层发起(客户端发起传入的),那么该层写操作就配置成Mandatory属性,要求调用方必须传入Transaction context;反之事务发起的层写操作应该设成required, 因为它可以控制事务的发起,回滚,提交等。
Programmatic Transaction Model应用的场景有: 1. 客户端bean发起一个事务,并把事务传播到调用的EJB中去,这些EJB用Declarative Transaction. 该方法解决了transation context不能在编程事务管理bean中传播的问题 2. 考虑到性能问题,有时我们只需要在关键的Case中需要用到事务,比如转账。其他周边Case不进行事务控制。这是可以考虑用编程事务。有时也称为Localized JTA Transations。声明式的事务可能没有编程式的灵活。个人理解,瞎猜的,没有用过。 3. 长事务, 放在一个stateful sessionBean中。虽然是一种Poor Design, 但还只有编程事务好处理。因为声明事务不好去划分事务的边界(propagation 和 isolation level). 个人理解,瞎猜的,没有用过。
一般序列化的方式有: 1. 通过JDK 的Serializable接口序列化成二进制字节流 RMI,EJB,分布式应用中需要用到 注意序列化的是类的数据成员,而不是方法 1.1 可以通过Externalizable接口( readExternal, writeExternal)定制Seriealizable过程 1.2 三种情况不会序列化 1)static field,序列化的是对象的状态 2)transient 类变量 3)父类成员变量(由父类负责序列化) 2. 序列化成XML XML-RPC,SOAP等序列化成XML进行Web Service之类的远程调用 常用的框架有:xstream, JAXB,etc. 3. 序列化成JSON(Javascript Object Notation) 轻量级的序列化方式
JAX-WS是JAX-RPC的下一个版本,它们的区别有: 1. JAX-RPC支持SOAP 1.1 JAX-WS支持SOAP 1.1 和 SOAP 1.2 2. JAX-RPC 对应的是Java 1.4 JAX-WS 对应的是 Java 5 3. JAX-RPC 有自己的XML - Java 映射模型 JAX-WS 采用 JAXB 4. JAX-WS 引入了异步,动态服务器模型等功能 5. JAX-RPC 支持WS-I Basic Profile V1.0 JAX-WS 支持WS-I Basic Profile V1.1 应该是互操作性更好了
bloom filter 用于测试一个元素是否在一个很大的数据集中。方法是利用多个hash函数,数据集中的元素通过hash函数到一个位置。查询时,做相同的hash查找。只要有一个hash函数没有match到对应的位置就可以判定该元素不在数据集中。所以该方法可能有false positive但一定没有false Negative。 2. suffix array/tree 把一个字符串的所有后缀字符串按字典排序,另外还可以加上LCP(Longest Common Prefix)