----2016----

---------------------------------------------
springBoot 的jdbc连接池
默认使用tomcat的连接池
JdbcTemplate.dataSource.poolProperties 中有一切,甚至是密码
默认的maxActive 是100

由于网络的一些问题(),会造成连接池的不可用
com.microsoft.sqlserver.jdbc.SQLServerException: 该连接已关闭。
这几个参数能保证及时网络有问题, 连接池也是可用的
testWhileIdle=true
testOnBorrow=true
validationQuery=select 1
removeAbandoned=true


--------------------------------------
tomcat的maxThread 500限制测试
http://blog.csdn.net/jackpk/article/details/32137483


----------------------------------------------
如何查看系统的并发数(某段时间)
accessLog ?
接口项目是可以通过accessLog来计算, web项目则不行, 会有很多的resource文件加载
web项目可以用这种方式
grep -v ".js\|.css\|.html\|.png" access_log.2016-08-22.log


http://www.xuebuyuan.com/661140.html --参数详情
http://www.cnblogs.com/huligong1234/p/4220017.html --增加配置 Tomcat通过%D或%T统计请求响应时间


AppServer的
cat access_log.2016-08-21.log |wc -l
--> 519310 = 每秒6个请求
grep -v "queryRollingMessage" access_log.2016-08-21.log |wc -l
--> 91812 排除了微聊轮播后的数据

PNS的
每天1454636 = 17个/秒
高峰7850/分钟 = 130个/秒 通过awk来计算
参考 http://huoding.com/2013/01/26/215


使用awk来分析accessLog 的访问量分布情况
awk -F: '{count[$2":"$3]++}END {for (minute in count) print minute, count[minute]}' localhost_access_log.2016-08-21.txt | sort > count.log
awk -F: '{count[$2]++}END {for (hour in count) print hour, count[hour]}' access_log.2016-08-22.log | sort > count2.log

sort -n -r -k 2 count.log

SpringBoot
server.tomcat.max-threads=2000 默认
server.tomcat.accesslog.enabled=true 可以 默认为false
server.tomcat.access-log-enabled=true 没有效果
server.tomcat.basedir=/home/log/${spring.application.name}
还有线程delay的
server.tomcat.background-processor-delay=30


-------------------------------------------------------
秒杀系统 --业务上是个性价比很低的系统

---锁
java的synchronized 针对的是一个JVM, 而对于集群环境没啥用, 只能用集中式缓存和DB中控制

---纯技术上
1, CDN
2, nginx 拒绝请求
3, cache
4, 乐观锁
5, queue 异步回复结果或是比较长的时间

---业务上
1, 验证码 --防止机器人
2, 黄牛账号分析

---负载量
吞吐量QPS(Query)
一个业务请求平均响应时间100ms
集群中有10tomcat 每台的maxThread是500个
QPS = 10*500/0.1 = 5w(QPS)

--其他
独立部署,以防对现有网站的冲击
秒杀商品页面静态化+cdn
租借阿里云
CDN nginx tomat db 数据量层层减少


---------------------------------------------------
spring的RestTemplate使用
getForObject postForObject 是 exchange的简化版, 没有Header
以前公司用的是easyrest

RestTemplate rt = new RestTemplate();
// String url = "http://pns.dooioo.com/message/scrollListRich/165641/1009";
// String forObject = rt.getForObject(url, String.class);
// System.out.println(forObject);

HttpEntity entity = new HttpEntity(body);
ResponseEntity exchange = rt.exchange(url, HttpMethod.POST, entity , JSONObject.class);
System.out.println(exchange.getBody());




---------------------------------------------------
利用Guava的Joiner, 将List转换为逗号分隔符


List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
String str = Joiner.on(",").join(list);



--------------------------------------------
tomcat在catalina.sh中修改内存参数, 有时会被setenv.sh中的参数覆盖


--------------------------------------------
stream()有点用处的地方


userCodeSet = subOrgList.stream().map(Employee::getUserCode).collect(Collectors.toSet());
/*for (Employee employee : subOrgList) {
userCodeSet.add(employee.getUserCode());
}*/



--------------------------------------------
琪琪学习
1, 上传控件问题
a> 控件中缺少一个参数, 在console中可以看到error
b> 成功时没有callback, 搜索successCallback关键字 返回的对象需要被解析成json,否则报错,catch后没有处理
c> 后端接受文件时用 @RequestParam("fileObject") MultipartFile file 需要修改文件名

2, 其他
a> 当页面编码为GBK时, 会影响到后面加载JS的编码, 导致加载失败 用$.getScript()可以检验是否加载js成功
b> $.ajax 中的dataType:"json" 是用来表明返回对象的类型, contentType: "application/json; charset=GBK", 是用来表示request的类型

3, 页面
a>
可以用来显示出db中文本自带的换行符, 
  
style="white-space: pre-line;" 用于过长的文本的换行
b> 图片没有显示全 用 background-size: contain;
字和图片挤在一起用 padding-left: 25px;
c> header加载不出来 是由于js css div之间的顺序关系, js自己也有顺序关系


--------------------------------------------
sql 列转行
http://www.cnblogs.com/maanshancss/archive/2013/03/13/2957108.html


SELECT id,
MAX(CASE type WHEN 1 THEN countUserData ELSE 0 END) as '1',
MAX(CASE type WHEN 2 THEN countUserData ELSE 0 END) as '2',
MAX(CASE type WHEN 3 THEN countUserData ELSE 0 END) as '3'
FROM tt
GROUP BY id;


公司

SELECT x.backgroundId,
MAX(CASE type WHEN 1 THEN countUserData ELSE 0 END) as userDataType1,
MAX(CASE type WHEN 2 THEN countUserData ELSE 0 END) as userDataType2,
MAX(CASE type WHEN 3 THEN countUserData ELSE 0 END) as userDataType3
FROM (select t2.backgroundId, t2.type , count(t2.backgroundId) as countUserData
from t_background_user_data t2 with(nolock)
group by t2.backgroundId , t2.type) x
GROUP BY x.backgroundId


可以改写成 不用MAX
这个就是典型的行转列的用法, case when 的升级版

select t2.backgroundId
,COUNT(CASE type WHEN 1 THEN backgroundId END) as userDataType1
,COUNT(CASE type WHEN 2 THEN backgroundId END) as userDataType2
,COUNT(CASE type WHEN 3 THEN backgroundId END) as userDataType3
from t_background_user_data t2 with(nolock)
group by t2.backgroundId



[size=large][color=red]行转列 核心就是用的聚合函数[/color][/size]
数字的值是可以用 count, 但是string则不行, 需要用for xml的方式


select t.userCode,t.conversationId,
(
select t2.customerId + ',' from t_mircoChat_complain t2
where t2.userCode = t.userCode and t2.conversationId = t.conversationId
FOR XML PATH('')
) as ids
from dbo.t_mircoChat_complain t --where t.userCode =83074 and t.conversationId = '56e2c0d42627f372f8d00fa1'
group by t.userCode, t.conversationId;


还可以在java端用一次主查询加上n次子查询来做

--------------------------------------------
DNS也可以做负载均衡 但是需要很好的网络背景知识
dig 命令可以查询dns解析的地址, 属于系统管理员范围
dig www.baidu.com +short


www.a.shifen.com.
115.239.211.112
115.239.210.27


dig www.baidu.com +trace

http://www.2cto.com/os/201408/325875.html

--------------------------------------------
varchar 和 nvarchar的区别
一般如果用到中文或者其它特殊字符,我就会使用n开头的类型,否则的话直接使用var开头的。

nvarchar 字节的存储大小是所输入字符个数的两倍

varchar(50) 可以存放50个英文. 50个中文会报错
nvarchar(50) 可以存放50个中文.


--------------------------------------------
lambda 实现匿名内部类


String query = "SELECT first_name, last_name, age" +
" from person where person.id = " + id;

RowMapper rowMapper = new RowMapper() {
@Override
public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Person(rs.getString(1), rs.getString(2), rs.getInt(3));
}
};
return jdbcTemplate.queryForObject(query, rowMapper);

/* return jdbcTemplate.queryForObject(query, (resultSet, i) -> {
return new Person(resultSet.getString(1), resultSet.getString(2), resultSet.getInt(3));
});*/



--------------------------------------------
main vs JUnit
main在使用到一些spring.xml或是memcache等系统资源时无法结束,
需要手动System.exit(0)来结束, 而Junit则没这个问题


--------------------------------------------
memcache

set可以新增或是更新 add只能新增(一般不用)
gets 多返回了一个casId, 用来进行cas操作, 如果casId不同的话, 可以用while循环加sleep个10ms来轮询

boolean writelock = true;
int retNum = 100;
while (writelock && retNum-- > 0){
writelock = false;
try {
GetsResponse> getsResponse = fyMemcachedClient.gets(empNo.toString(),1000);
if(getsResponse == null || getsResponse.getValue() == null){

}else{
Set set = getsResponse.getValue();
set.remove(propertyId+","+session.getId());
if (!fyMemcachedClient.cas(empNo.toString(), 3600*12, set, getsResponse.getCas())) {
writelock = true;
Thread.sleep(10);
}
}
} catch (TimeoutException | InterruptedException | MemcachedException e) {
e.printStackTrace();
}

}


--------------------------------------------
springMVC 静态资源配置
http://www.cnblogs.com/yank/p/4477204.html

---------------------------------------------
SQL Server 中id递增的 不能手动指定, 需要重新设置index
DBCC checkident(T_Business_Side,reseed,1018);

更好的办法是
SET IDENTITY_INSERT dbo.xxx ON
GO

直接指定id, 之后需要OFF掉
--------------------------------------
soapUI 中的Header添加
Content-Type text/html; charset=GBK
可以解决
1, 请求被fastjson拦截
2, 报文体不支持中文


--------------------------------------
CPU 50% 4核机器

private static void cpu50() throws InterruptedException {
new Thread(() -> {
long l = 0;
while (true) {
l++;
}
}).start();

new Thread(() -> {
long l2 = 0;
while (true) {
l2++;
}
}).start();

Thread.sleep(Long.MAX_VALUE);
}



--------------------------------------
CPU 100%问题 top --> jstack
http://www.tuicool.com/articles/AbeeQz
http://bbs.csdn.net/topics/390666435


---------------------------------------
linux发送邮件
http://blog.sina.com.cn/s/blog_48ab118d0101fo3q.html
http://www.linuxidc.com/Linux/2014-10/107946.htm

--------------------------------------
微服务研究下
【Feign】 RPC
【Eureka】 服务发现(仪表盘)
【Configuration】 git
【查看关联了几个service】 http://ms.dooioo.org/admin/health

---------------------------------------
用(String) 强转碰到null也不会出问题, 比toString() 更安全


Object obj = null;
System.out.println((String)obj);
System.out.println(obj.toString());



--------------------------------------------
微服务存在的问题
1> Controller中的异常被外部框架捕获了, 无法打印出堆栈信息
2> 历史价格会调用后台 20(页)*3(其他接口)+1 = 61次接口请求, 速度慢.
而且由于是分页查询,无法做缓存


--------------------------------------------
接口返回list,需要转换成标准的json
Object json = JSON.toJSON(list)


--------------------------------------------
sqlserver 的分页太烂了
http://blog.csdn.net/qiaqia609/article/details/41445233

推荐的代码是
定位法 (利用ID大于多少)

语句形式:


select top 10 * from tbl_FlightsDetail where FlightsDetailID>(
select max(FlightsDetailID) from (
select top 3000000 FlightsDetailID from tbl_FlightsDetail order by FlightsDetailID
) as t
) order by FlightsDetailID

--------------------------------------------
row_number 的使用


[img]http://dl2.iteye.com/upload/attachment/0117/6617/cdad9349-3ea8-3c71-86d6-79ed35adeeeb.png[/img]


--------------------------------------------
ArrayList 没有concurrent版本, hashMap的concurrent版是基于分桶的.

LinkedHashSet 可以按照插入顺序排序

--------------------------------------------
maven冲突
commons-lang-2.6 和commons-lang-3.7 很容易出现冲突(有些jar包底层依赖于2.6), 编译的时候能通过, 打包的时候无法解析StringUtils
在 Dependency Hierarchy中将2.6版本间接加载的内容去掉, 将项目代码中的StringUtils改成3.7, 再将2.6的内容加回去


--------------------------------------------
select * from 视图 很可能由于查询的数据太多导致吃不到索引, 走全表扫描
PNS v_message_history 中去掉readTime和status字段.(某些用户有大量消息的时候发生)

第一次查询慢 第二次快的现象
可能是第一次全表扫,需要读磁盘,把数据加到内存里。间隔很短的第二次应该就直接内存了
过一段时间,内存的数据没有访问会被刷走,再来访问,就要重新走磁盘


--------------------------------------------
线上发布应用是最好用kill 不加-9 [就是-15]来停, 这样能保证所有当前正在运行的线程能顺利结束
如果实在停不了的话再用 kill -9


--------------------------------------------
删除1234月份的日志
info2016[1234].log

--------------------------------------------
log4j日志保留天数
DailyRollingFileAppender 不支持最大日志数量
http://blog.sina.com.cn/s/blog_6f505d710101bq1e.html

--------------------------------------
起线程异步调用
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(() -> behaviorLogService.insertLoginLog(behaviorLog));

//new Thread(() -> behaviorLogService.insertLoginLog(behaviorLog));



--------------------------------------
maven-shade-plugin 取代 maven-assembly-plugin
assembly 在打spring包时有问题
http://chenzhou123520.iteye.com/blog/1706242
在META-INF下会有多余的以SF结尾的文件,删除后不会出现次问题

--------------------------------------
数据库设计 -- free style
高并发 走cache
复杂查询 走solr
灵活性 走json / mongodb
海量数据查询 走hbase rowkey


-----------------------------------
查看linux 的ip
用InetAddress.getLocalHost().getHostAddress(); 的方式只能看到127.0.0.1
javac -d . TristanAsync.java
java com/dooioo/microChartTool/asc/TristanAsync


public static InetAddress getLocalHost() {
Enumeration netInterfaces = null;
try {
netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
NetworkInterface ni = netInterfaces.nextElement();
Enumeration ips = ni.getInetAddresses();
while (ips.hasMoreElements()) {
InetAddress ip = ips.nextElement();
if (ip.isSiteLocalAddress()) {
return ip;
}
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}



-----------------------------------
springMVC 学习
1, 创建maven项目, 选择webapp的archetype
2, JSP中用${error}来获取model中的值
3, 在web.xml中用DispatcherServlet来取代原来的ContextLoaderListener
4, DispatcherServlet 对应的xml中,只需要一个 就ok
5, 拦截器 loginInterceptor 某些路径不需要拦截(/api,/static等). [房源]
6, 异常处理 @ExceptionHandler BaseController
7, 视图解析器
return "/WEB-INF/jsp/"+pageName+".jsp" 变成了 return pageName;

8,



-----------------------------------
grep匹配符 .*
grep "V4.*scrollList duration" info.log|less

--------------------------------
按日统计 按月统计
select CONVERT(varchar(10), t.createTime, 23) as createDate, count(1)
from t_message t with(nolock)
where t.createTime > '2016-05-01'
group by CONVERT(varchar(10), t.createTime, 23)
order by CONVERT(varchar(10), t.createTime, 23) asc;

select CONVERT(char(7), t.createTime, 23) as createDate, count(1)
from t_message t with(nolock)
where t.createTime > '2016-01-01'
group by CONVERT(char(7), t.createTime, 23)
order by CONVERT(char(7), t.createTime, 23) asc;

select getdate();

SELECT CONVERT(varchar(100),getdate(),23) now;

【历史表一起统计】
select CONVERT(char(7), t.createTime, 23) as createDate, count(1)
from dbo.T_Message_Read t with(nolock)
where t.createTime > '2016-01-01'
group by CONVERT(char(7), t.createTime, 23)
--order by CONVERT(char(7), t.createTime, 23) asc
UNION all
select CONVERT(char(7), t.createTime, 23) as createDate, count(1)
from dbo.T_Message_Read_History t with(nolock)
where t.createTime > '2016-01-01'
group by CONVERT(char(7), t.createTime, 23)
order by CONVERT(char(7), t.createTime, 23) asc;
-----------------------------
短信供应商延迟的问题, 可以在短信文本中写上日期, 这样就能确定是我们的问题还是供应商的问题了

--------------------------------
PNS发送消息改成异步的风险

如果直接返回一个ok, 外部系统循环调用的话就会,pns这里就可能出现并发的问题.
当然如果外系统用开线程的方式并行来调的话, 这就不可避免的.
5秒钟的超时时间, 至少可以保护pns的压力.
pns后台逻辑还是很复杂的, 大量的数据库读写, leanCloud通讯, 所以出现并发问题会很麻烦, 不改了, 用blockingQueue的话会有其他方面的问题


--------------------------------

端口占用问题
netstat -anp | grep 端口
ps -aux | grep pid

--------------------------------
js
js可以通过 window.location.href 获取url中的参数
debugger 可以强行打个断点

-----------------------------------------
JDK7自动关闭的try语句
try (字节流输出输出等可能异常的语句)
{ }
catch (Exception e) {
e.printStackTrace();
}
可以不用显式关闭

-----------------------------------------
用jvisualvm (profiler - cpu) 可以看到
1> 哪些方法耗时多
2> 哪些方法调用次数多
3> 调用的顺序关系

-----------------------------------------
jar包读取外面的配置文件, 可以用这种方式, 同时支持linux和windows

Properties p = new Properties();
InputStream in = null;
try{
in = new FileInputStream("/home/app/microChat/microChat.properties");
}catch(Exception e){
log.info("use windows property");
in=new FileInputStream("D:\\eclipse-jee-luna-SR2-win32-x86_64\\svn\\microChatTool\\src\\main\\resources\\microChat.properties");
}
p.load(in);
in.close();



-----------------------------------------
assembly 打包, 将依赖的jar包打在一起
http://blog.csdn.net/czp11210/article/details/47808211

如果改了unpack属性后, 本项目的源代码就没了


---------------------------------------------------
java.sql.Date 只存储日期数据不存储时间数据
// 会丢失时间数据
preparedStatement.setDate(1, new java.sql.Date(date.getTime()));
//可以这样来处理
preparedStatement.setTimestamp(1, new java.sql.Timestamp(new java.util.Date().getTime()));


----------------------------------------------
java的URLEcnode不会对特殊字符编码

例如
原始代码
select * from _Conversation where attr.phone='18529'

URLEcnode后的. 手动将+号转成%20
select%20*%20from%20_Conversation%20where%20attr.phone%3D%2718529%27

而标准的应该的是(通过CURL -v 打印出来的)
select%20%2A%20from%20%5FConversation%20where%20attr%2Ephone%3D%2718529%27


----------------------------------------------
JSONObject toJSONString toJSON 区别
String jsonString = JSONObject.toJSONString(esEmployee);
可以吃到@JSONField中定义的格式
@JSONField(format="yyyy-MM-dd'T'HH:mm:ssZ")
private Date occurTime;

String jsonString = JSONObject.toJSON(esEmployee).toString();
则无法吃到, occurTime还是显示long的格式


-----------------------------------------
响应式布局
visible-xs-block


-----------------------------------
IdentityHashMap可以保存相同key值, 但是如果是数字的话一定要大于127


IdentityHashMap imap = new IdentityHashMap();

int a = 127;
imap.put(a, 5);
imap.put(a, 6);
imap.put(a, 7);

System.out.println(imap.size());



---------------------------------------
server端返回的数据都是string的, 即使声明成integer的话, 客户端也转不了.
服务端

@Override
public ResponseEntity microChatData2(String param, String startDate, String endDate) {
List list = behaviorLogService.microChatData2(param, startDate, endDate);
return ResponseEntity.ok(list);
}


客户端

List result = RestClient.exchange(url,HttpMethod.GET,List.class);

for (Integer r : result) {
syso;
}



---------------------------------------
除法百分比

System.out.println(369 / 809);
System.out.println(369 % 809);

double x = (369 * 1.0 / 809) * 100;
System.out.println(x);
java.text.DecimalFormat df = new java.text.DecimalFormat("#.##");
System.out.println(df.format(x) +"%");



-------------------------------------
springMVC服务端如果是直接return个json对象, 用chrome或是api的方式 得到的是一个xml的对象.
需要将json对象转成string的
return ResponseEntity.ok(json.toString());


-------------------------------------------
Map 按照key倒排

String result = RestClient.exchange("http://localhost:9600/oms/v1/microChatData?param="+param,HttpMethod.GET,String.class);
Map map = (Map) JSONObject.parse(result);
TreeMap treeMap = new TreeMap(map);
for (String key : treeMap.descendingKeySet()) {
System.out.println(key +" " + treeMap.get(key));
}



-----------------------------------
mybatis的#,$ 区别
#是正对于string的 会在变量左右加上''
$则不会
例如userCode是integer的
要用 where t.userCode in (${userCode})
不能是 where t.userCode in (#{userCode})

参考 http://blog.csdn.net/downkang/article/details/12499197

---------------------------------
根据dao层对象查看数据库url
queryDao --> sqlSession --> exceptionTranslator --> dataSource -->url

---------------------------------------
性能监控 TOP --最靠谱
P CPU排序
M 内存排序

查看内存 --不准的
free -m

统计 -- 内存数据看不出的
vmstat 5 5
--------------------------------------------
一批数据更新/插入时可以用 虚拟表union all + inner join + not exists 的方式来做



update a set a.remark = #{remark}, a.updateTime = getDate(), readStatus = 1
from t_message_last a
inner join (

select #{appId} as appId, #{businessId} as businessId, #{userCode} as userCode

) b on a.userCode = b.userCode and a.appId = b.appId and a.businessId = b.businessId



insert into t_message_last(appId, businessId, userCode, businessName, remark, createTime, readStatus)
select a.*,#{businessName}, #{remark} , getDate(), 1
from (

select #{appId} as appId, #{businessId} as businessId, #{userCode} as userCode

) a
where not exists ( select 1 from t_message_last c where c.userCode =a.userCode and c.appId = #{appId} and c.businessId = #{businessId} );




----------------------
secureCRT有时在session中设置的编码没有效果, 在需要堡垒机跳转的情况
需要在global中设置

[img]http://dl2.iteye.com/upload/attachment/0115/5333/459e45de-a5e3-30fb-8ce2-64016850d565.png[/img]


-----------------------------------
rz sz 命令可以在secureCRT中上传下载文件

--------------------------

String[] ss = {"a","b","c"};
List asList = Arrays.asList(ss);
asList.remove("a");

这里会报错, Arrays.asList 出来的List没有实现remove方法.

可以用下列方式

String[] s = {"a","b","c"};
List list2 = new LinkedList();
Collections.addAll(list2, s);
list2.remove("a");
System.out.println(list2.size());



-----------------------------
ArrayList 和 LinkedList
LinkedList删除的速度比ArrayList快


----------------------------------
delete 和 insert写在一起

delete from t_message_read output deleted.msId,deleted.userCode,deleted.createTime,deleted.updateTime,deleted.status
into T_Message_Read_History (msId, userCode, createTime, updateTime, status) where msId < ?



------------------------------
left join on where
1. 对于left join,不管on后面跟什么条件,左表的数据全部查出来,因此要想过滤需把条件放到where后面
2. 对于inner join,满足on后面的条件表的数据才能查出,可以起到过滤作用。也可以把条件放到where后面。

 
select * from
(
SELECT m.userCode , m.appId, m.businessId, m.businessName, m.createTime,m.readStatus,m.remark
,CASE WHEN d.userCode IS NULL THEN 1 ELSE 0 END AS disturb
,ROW_NUMBER() OVER(partition BY m.businessId ORDER BY m.id DESC) AS rowId

FROM T_Message_Last m
left join dbo.T_Business_UnDisturb d
on d.bId = m.businessId and d.userCode = m.userCode where m.appId = 1000 and m.userCode = 104705
) c
where c.rowId = 1;


------------------
transient
某些不需要传给客户端的属性可以用transient来屏蔽掉

transient private String userCode;


------------------
泛型使用

public class Pagination {
private List list;
}


--------------
JDK8
list.stream()
.map().collect(Collectors.toList())
.collect(Collectors.groupingBy(PropertyView::getPropertyId))
.filter
.anyMatch


------------
微服务
Spring Boot 以web方式启动一个jar包. 和内嵌的jetty差不多
Spring Cloud 基于Spring Boot, 提供了一些路由服务 和loadBalance差不多


--------------
防止重复提交
1> 提交后重定向到一个GET页面,避免F5刷新页面.
2> 进入表单页时生成一个token分别放在session和request中,表单页用hidden的方式将request中的token发送到服务端, 服务端比较session和传递过来的token是否相同,并将session中的token清除.

--------------
AOP(@Aspect) 和 自定义拦截器(HandlerInterceptorAdapter)的区别
自定义拦截器能获得用户的request信息.
而AOP需要获得的话只有通过传递用户参数到Service层才可以,或是threadLocal
AOP可以用作memcached的更新
自定义拦截器可以用于避免单一用户表单同时提交.(注意这里不是重复提交)

--------------------
NoSql精粹
noSql 特点 无模式, 集群, 牺牲了一致性
悲观锁处理并发时,很容易导致"死锁"

数据库分布式
1, 切片
2, 复制 (主从/对等--写入时一致性风险性太大)

映射-化简 Map-Reduce
将执行逻辑放到数据库集群中, 而不是在JVM客户端中

电子商务平台
--购物车及会话数据 [键值DB]
--已完成的订单 [文档DB]
--库存及产品价格 [关系型DB]
--客户社交关系图 [图DB] (您的朋友还购买了)

-----------------------


dao层定义属性最好使用int 而不是integer
数据库中为空时Integer直接用来判断 == 1 时会有空指针异常 而int 有个默认的值0

--------------
dao中用String 声明也有可能是null 用String propertyNo = ""; 就没有问题

你可能感兴趣的:(LJ,json,操作系统,java)