一些实体只要求身份标识具有唯一性即可,如评论实体、博客实体或文章实体的身份标识,都可以使用自动增长的 Long 类型或者随机数与 UUID、GUID,这样的身份标识并没有任何业务含义。有些实体的身份标识则规定了一定的组合规则,例如公民实体、员工实体与订单实体的身份标识就不是随意生成的。遵循业务规则生成的身份标识体现了领域概念,例如公民实体的身份标识其实就是“身份证号”这一领域概念。定义规则的好处在于我们可以通过解析身份标识获取有用的领域信息,例如解析身份证号,可以直接获得该公民的部分基础信息,如籍贯、出生日期、性别等,解析订单号即可获知该订单的下单渠道、支付渠道、业务类型与下单日期等。
限界上下文是“分而治之”架构原则的体现,我们引入它的目的其实为了控制(应对)软件的复杂度,它并非某种固定的设计单元,我们不能说它就是模块、服务或组件,而是通过它来帮助我们做出高内聚低耦合的设计。只要遵循了这个设计,则限界上下文就可能成为模块、服务或组件。所以,文章《Bounded Contexts as a Strategic Pattern Beyond DDD》才会写到:“限界上下文体现的是高层的抽象机制,它并非编程语言或框架的产出工件,而是体现了人们对领域思考的本质。”
final is one of the most under-used features of Java. Whenever you compute a value and you know it will never be changed subsequently put a final on it. Why?
final lets other programmers (or you reviewing your code years later) know they don’t have to worry about the value being changed anywhere else.
If you get in the habit of always using final, when it is missing, it warns people reading your code there is a redefinition of the value elsewhere.
final won’t let you or someone else inadvertently change the value somewhere else in the code, often by setting it to null. final helps prevent or flush out bugs. It can sometimes catch an error where an expression is assigned to the wrong variable. You can always remove it later.
final helps the compiler generate faster code, though I suspect a clever compiler could deducing finality, even when the final is missing. final values can sometimes be in-lined as literals. They can be further collapsed at compile time in other final expressions.
I have got into the habit of using final everywhere, even on local variables and if I am in doubt, I use final on every declaration then take it off when the compiler points out that I modified it elsewhere. When I read my own code, a missing final is a red flag there is something complicated going on to compute a value.
If you reference a static final in another class, that value often becomes part of your class at compile time. The source class then need not be loaded to get the value and the source class need not even be included in the jar. This helps conserve RAM (Random Access Memory) and keep your jars small.
At the machine language level, static finals can be implemented with inline literals, the most efficient form of addressing data.
A little known feature of Java is blank finals. You can declare member variables final, but not declare a value. This forces all constructors to initialise the blank final variables. A final idiom
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public void test() { // Use of final to ensure a variable is always assigned a value, // and is assigned a value once and only once. int a = 4; final int x;
if (a > 0) { x = 14; } else if (a < 0) { x = 0; } else { x = 3; } System.err.println(x); }
public void testSwitch(){ final String name; int pluginType = 3; switch (pluginType) { case 1: name = "Candidate Stuff"; //break; //should have handled all the cases for pluginType case 2: name = "fff"; } // code, code, code // Below is not possible with final //name = "Whoops bug"; }
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { /** Main lock guarding all access */ final ReentrantLock lock; public int remainingCapacity() { final ReentrantLock lock = this.lock; lock.lock(); try { return items.length - count; } finally { lock.unlock(); } }
Doug Lea给的答复是
It’s ultimately due to the fundamental mismatch between memory models and OOP Just about every method in all of j.u.c adopts the policy of reading fields as locals whenever a value is used more than once.This way you are sure which value applies when.This is not often pretty, but is easier to visually verify. The surprising case is doing this even for “final” fields.This is because JVMs are not always smart enough to exploit the fine points of the JMM and not reload read final values, as they would otherwise need to do across the volatile accesses entailed in locking. Some JVMs are smarter than they used to be about this, but still not always smart enough.
现在我们以 x86 处理器为例,说明 final 语义在处理器中的具体实现。 上面我们提到,写 final 域的重排序规则会要求译编器在 final 域的写之后,构造函数 return 之前,插入一个 StoreStore 障屏。读 final 域的重排序规则要求编译器在读 final 域的操作前面插入一个 LoadLoad 屏障。
由于 x86 处理器不会对写 - 写操作做重排序,所以在 x86 处理器中,写 final 域需要的 StoreStore 障屏会被省略掉。同样,由于 x86 处理器不会对存在间接依赖关系的操作做重排序,所以在 x86 处理器中,读 final 域需要的 LoadLoad 屏障也会被省略掉。也就是说在 x86 处理器中,final 域的读 / 写不会插入任何内存屏障!
---------------------------- END OF INNODB MONITOR OUTPUT ============================
打开锁监控,可以确定一下常用语句的锁信息
执行完一条SQL,使用SHOW ENGINE INNODB STATUS打印出锁信息
1 2 3 4
delete from invoice_collection_info where id=1275244823997059072
TABLE LOCK table `assist`.`invoice_collection_info` trx id 1636893 lock mode IX RECORD LOCKS space id 18491 page no 211 n bits 104 index `PRIMARY` of table `assist`.`invoice_collection_info` trx id 1636893 lock_mode X locks rec but not gap
delete语句,根据主键删除操作;可以明显看出上了表锁IX model,还有一个主键索引锁
其实如果有二级索引,还会有二级索引锁,但那是隐式锁,所以没有显示出来,后面会有试验让隐式锁显示化
使用二级索引删除操作
1 2 3 4 5 6 7 8 9 10
delete FROM invoice_item WHERE ( collection_id = 1275244823997059072 );
TABLE LOCK table `assist`.`invoice_item` trx id 1636964 lock mode IX RECORD LOCKS space id 18493 page no 4 n bits 784 index `idx_collection_id` of table `assist`.`invoice_item` trx id 1636964 lock_mode X locks rec but not gap Record lock, heap no 563 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 8; hex 91b2946930001000; asc i0 ;; 1: len 8; hex 91b2ae5d61401000; asc ]a@ ;;
RECORD LOCKS space id 18493 page no 12 n bits 96 index `PRIMARY` of table `assist`.`invoice_item` trx id 1636964 lock_mode X locks rec but not gap Record lock, heap no 28 PHYSICAL RECORD: n_fields 23; compact format; info bits 0
先在二级索引上加锁,再在对应的主键索引上加锁
使用二级索引查询
1 2 3 4 5 6
select * from invoice_collection_info where invoice_uiq_flag = '031001900104-62079412' for update
TABLE LOCK table `assist`.`invoice_collection_info` trx id 1636947 lock mode IX RECORD LOCKS space id 18491 page no 642 n bits 344 index `idx_uniflag` of table `assist`.`invoice_collection_info` trx id 1636947 lock_mode X locks rec but not gap
RECORD LOCKS space id 18491 page no 496 n bits 96 index `PRIMARY` of table `assist`.`invoice_collection_info` trx id 1636947 lock_mode X locks rec but not gap
从日志中看出,先在invoice_uiq_flg二级索引上加锁,再在主键索引加锁
使用主键更新操作
1 2 3 4
update invoice_collection_info set invoice_uiq_flag = '031200190010-62079412' WHERE ( id = 1275244823997059072 ); TABLE LOCK table `assist`.`invoice_collection_info` trx id 1636958 lock mode IX RECORD LOCKS space id 18491 page no 741 n bits 88 index `PRIMARY` of table `assist`.`invoice_collection_info` trx id 1636958 lock_mode X locks rec but not gap