2016
来源:互联网 发布:动漫人物设计软件 编辑:程序博客网 时间:2024/04/26 10:37
-------------------------------------------------------
秒杀系统
---锁
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
租借阿里云
---------------------------------------------------
spring的RestTemplate使用
getForObject postForObject 是 exchange的简化版, 没有Header
以前公司用的是easyrest
[code="java"]
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<String>(body);
ResponseEntity<JSONObject> exchange = rt.exchange(url, HttpMethod.POST, entity , JSONObject.class);
System.out.println(exchange.getBody());
[/code]
---------------------------------------------------
利用Guava的Joiner, 将List转换为逗号分隔符
[code="java"]
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
String str = Joiner.on(",").join(list);
[/code]
--------------------------------------------
tomcat在catalina.sh中修改内存参数, 有时会被setenv.sh中的参数覆盖
--------------------------------------------
stream()有点用处的地方
[code="java"]
userCodeSet = subOrgList.stream().map(Employee::getUserCode).collect(Collectors.toSet());
/*for (Employee employee : subOrgList) {
userCodeSet.add(employee.getUserCode());
}*/
[/code]
--------------------------------------------
琪琪学习
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> <pre>可以用来显示出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
[code="java"]
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;[/code]
公司
[code="java"]
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
[/code]
可以改写成 不用MAX
这个就是典型的行转列的用法, case when 的升级版
[code="java"]
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
[/code]
[size=large][color=red]行转列 核心就是用的聚合函数[/color][/size]
数字的值是可以用 count, 但是string则不行, 需要用for xml的方式
[code="java"]
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;
[/code]
还可以在java端用一次主查询加上n次子查询来做
--------------------------------------------
DNS也可以做负载均衡 但是需要很好的网络背景知识
dig 命令可以查询dns解析的地址, 属于系统管理员范围
dig www.baidu.com +short
[code="java"]
www.a.shifen.com.
115.239.211.112
115.239.210.27
[/code]
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 实现匿名内部类
[code="java"]
String query = "SELECT first_name, last_name, age" +
" from person where person.id = " + id;
RowMapper<Person> rowMapper = new RowMapper<Person>() {
@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));
});*/
[/code]
--------------------------------------------
main vs JUnit
main在使用到一些spring.xml或是memcache等系统资源时无法结束,
需要手动System.exit(0)来结束, 而Junit则没这个问题
--------------------------------------------
memcache
set可以新增或是更新 add只能新增(一般不用)
gets 多返回了一个casId, 用来进行cas操作, 如果casId不同的话, 可以用while循环加sleep个10ms来轮询
[code="java"]
boolean writelock = true;
int retNum = 100;
while (writelock && retNum-- > 0){
writelock = false;
try {
GetsResponse<Set<String>> getsResponse = fyMemcachedClient.gets(empNo.toString(),1000);
if(getsResponse == null || getsResponse.getValue() == null){
}else{
Set<String> 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();
}
}
[/code]
--------------------------------------------
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核机器
[code="java"]
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);
}
[/code]
--------------------------------------
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() 更安全
[code="java"]
Object obj = null;
System.out.println((String)obj);
System.out.println(obj.toString());
[/code]
--------------------------------------------
微服务存在的问题
1> Controller中的异常被外部框架捕获了, 无法打印出堆栈信息
2> 历史价格会调用后台 20(页)*3(其他接口)+1 = 61次接口请求, 速度慢.
而且由于是分页查询,无法做缓存
--------------------------------------------
接口返回list,需要转换成标准的json
Object json = JSON.toJSON(list)
--------------------------------------------
sqlserver 的分页太烂了
http://blog.csdn.net/qiaqia609/article/details/41445233
推荐的代码是
定位法 (利用ID大于多少)
语句形式:
[code="java"]
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
[/code]
--------------------------------------------
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
--------------------------------------
起线程异步调用
[code="java"]ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(() -> behaviorLogService.insertLoginLog(behaviorLog));
//new Thread(() -> behaviorLogService.insertLoginLog(behaviorLog));[/code]
--------------------------------------
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
[code="java"]
public static InetAddress getLocalHost() {
Enumeration<NetworkInterface> netInterfaces = null;
try {
netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
NetworkInterface ni = netInterfaces.nextElement();
Enumeration<InetAddress> 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;
}
[/code]
-----------------------------------
springMVC 学习
1, 创建maven项目, 选择webapp的archetype
2, JSP中用${error}来获取model中的值
3, 在web.xml中用DispatcherServlet来取代原来的ContextLoaderListener
4, DispatcherServlet 对应的xml中,只需要一个<context:component-scan/> 就ok
5, 拦截器 loginInterceptor 某些路径不需要拦截(/api,/static等). [房源]
6, 异常处理 @ExceptionHandler BaseController
7, 视图解析器
return "/WEB-INF/jsp/"+pageName+".jsp" 变成了 return pageName;
8, <!-- 支持异步方法 / 支持定时任务-->
<task:annotation-driven/>
-----------------------------------
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
[code="java"]
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();
[/code]
-----------------------------------------
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
[code="java"]
IdentityHashMap<Integer, Integer> imap = new IdentityHashMap<Integer, Integer>();
int a = 127;
imap.put(a, 5);
imap.put(a, 6);
imap.put(a, 7);
System.out.println(imap.size());
[/code]
---------------------------------------
server端返回的数据都是string的, 即使声明成integer的话, 客户端也转不了.
服务端
[code="java"]
@Override
public ResponseEntity<?> microChatData2(String param, String startDate, String endDate) {
List<Integer> list = behaviorLogService.microChatData2(param, startDate, endDate);
return ResponseEntity.ok(list);
}
[/code]
客户端
[code="java"]
List<Integer> result = RestClient.exchange(url,HttpMethod.GET,List.class);
for (Integer r : result) {
syso;
}
[/code]
---------------------------------------
除法百分比
[code="java"]
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) +"%");
[/code]
-------------------------------------
springMVC服务端如果是直接return个json对象, 用chrome或是api的方式 得到的是一个xml的对象.
需要将json对象转成string的
return ResponseEntity.ok(json.toString());
-------------------------------------------
Map 按照key倒排
[code="java"]
String result = RestClient.exchange("http://localhost:9600/oms/v1/microChatData?param="+param,HttpMethod.GET,String.class);
Map<String,Integer> map = (Map<String, Integer>) JSONObject.parse(result);
TreeMap<String,Integer> treeMap = new TreeMap<String,Integer>(map);
for (String key : treeMap.descendingKeySet()) {
System.out.println(key +" " + treeMap.get(key));
}
[/code]
-----------------------------------
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 的方式来做
[code="java"]
<update id="batchUpdate" parameterType="map">
update a set a.remark = #{remark}, a.updateTime = getDate(), readStatus = 1
from t_message_last a
inner join (
<foreach collection="userCodeSet" item="userCode" separator=" union all " open="(" close=")">
select #{appId} as appId, #{businessId} as businessId, #{userCode} as userCode
</foreach>
) b on a.userCode = b.userCode and a.appId = b.appId and a.businessId = b.businessId
</update>
<insert id="batchInsert" parameterType="map">
insert into t_message_last(appId, businessId, userCode, businessName, remark, createTime, readStatus)
select a.*,#{businessName}, #{remark} , getDate(), 1
from (
<foreach collection="userCodeSet" item="userCode" separator=" union all " open="(" close=")">
select #{appId} as appId, #{businessId} as businessId, #{userCode} as userCode
</foreach>
) a
where not exists ( select 1 from t_message_last c where c.userCode =a.userCode and c.appId = #{appId} and c.businessId = #{businessId} );
</insert>
[/code]
----------------------
secureCRT有时在session中设置的编码没有效果, 在需要堡垒机跳转的情况
需要在global中设置
[img]http://dl2.iteye.com/upload/attachment/0115/5333/459e45de-a5e3-30fb-8ce2-64016850d565.png[/img]
-----------------------------------
rz sz 命令可以在secureCRT中上传下载文件
--------------------------
[code="java"]
String[] ss = {"a","b","c"};
List<String> asList = Arrays.asList(ss);
asList.remove("a");
[/code]
这里会报错, Arrays.asList 出来的List没有实现remove方法.
可以用下列方式
[code="java"]
String[] s = {"a","b","c"};
List<String> list2 = new LinkedList<String>();
Collections.addAll(list2, s);
list2.remove("a");
System.out.println(list2.size());
[/code]
-----------------------------
ArrayList 和 LinkedList
LinkedList删除的速度比ArrayList快
----------------------------------
delete 和 insert写在一起
[code="java"]
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 < ?
[/code]
------------------------------
left join on where
1. 对于left join,不管on后面跟什么条件,左表的数据全部查出来,因此要想过滤需把条件放到where后面
2. 对于inner join,满足on后面的条件表的数据才能查出,可以起到过滤作用。也可以把条件放到where后面。
[code="java"]
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;
[/code]
------------------
transient
某些不需要传给客户端的属性可以用transient来屏蔽掉
transient private String userCode;
------------------
泛型使用
[code="java"]
public class Pagination<T> {
private List<T> list;
}
[/code]
--------------
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 = ""; 就没有问题
秒杀系统
---锁
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
租借阿里云
---------------------------------------------------
spring的RestTemplate使用
getForObject postForObject 是 exchange的简化版, 没有Header
以前公司用的是easyrest
[code="java"]
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<String>(body);
ResponseEntity<JSONObject> exchange = rt.exchange(url, HttpMethod.POST, entity , JSONObject.class);
System.out.println(exchange.getBody());
[/code]
---------------------------------------------------
利用Guava的Joiner, 将List转换为逗号分隔符
[code="java"]
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
String str = Joiner.on(",").join(list);
[/code]
--------------------------------------------
tomcat在catalina.sh中修改内存参数, 有时会被setenv.sh中的参数覆盖
--------------------------------------------
stream()有点用处的地方
[code="java"]
userCodeSet = subOrgList.stream().map(Employee::getUserCode).collect(Collectors.toSet());
/*for (Employee employee : subOrgList) {
userCodeSet.add(employee.getUserCode());
}*/
[/code]
--------------------------------------------
琪琪学习
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> <pre>可以用来显示出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
[code="java"]
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;[/code]
公司
[code="java"]
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
[/code]
可以改写成 不用MAX
这个就是典型的行转列的用法, case when 的升级版
[code="java"]
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
[/code]
[size=large][color=red]行转列 核心就是用的聚合函数[/color][/size]
数字的值是可以用 count, 但是string则不行, 需要用for xml的方式
[code="java"]
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;
[/code]
还可以在java端用一次主查询加上n次子查询来做
--------------------------------------------
DNS也可以做负载均衡 但是需要很好的网络背景知识
dig 命令可以查询dns解析的地址, 属于系统管理员范围
dig www.baidu.com +short
[code="java"]
www.a.shifen.com.
115.239.211.112
115.239.210.27
[/code]
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 实现匿名内部类
[code="java"]
String query = "SELECT first_name, last_name, age" +
" from person where person.id = " + id;
RowMapper<Person> rowMapper = new RowMapper<Person>() {
@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));
});*/
[/code]
--------------------------------------------
main vs JUnit
main在使用到一些spring.xml或是memcache等系统资源时无法结束,
需要手动System.exit(0)来结束, 而Junit则没这个问题
--------------------------------------------
memcache
set可以新增或是更新 add只能新增(一般不用)
gets 多返回了一个casId, 用来进行cas操作, 如果casId不同的话, 可以用while循环加sleep个10ms来轮询
[code="java"]
boolean writelock = true;
int retNum = 100;
while (writelock && retNum-- > 0){
writelock = false;
try {
GetsResponse<Set<String>> getsResponse = fyMemcachedClient.gets(empNo.toString(),1000);
if(getsResponse == null || getsResponse.getValue() == null){
}else{
Set<String> 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();
}
}
[/code]
--------------------------------------------
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核机器
[code="java"]
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);
}
[/code]
--------------------------------------
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() 更安全
[code="java"]
Object obj = null;
System.out.println((String)obj);
System.out.println(obj.toString());
[/code]
--------------------------------------------
微服务存在的问题
1> Controller中的异常被外部框架捕获了, 无法打印出堆栈信息
2> 历史价格会调用后台 20(页)*3(其他接口)+1 = 61次接口请求, 速度慢.
而且由于是分页查询,无法做缓存
--------------------------------------------
接口返回list,需要转换成标准的json
Object json = JSON.toJSON(list)
--------------------------------------------
sqlserver 的分页太烂了
http://blog.csdn.net/qiaqia609/article/details/41445233
推荐的代码是
定位法 (利用ID大于多少)
语句形式:
[code="java"]
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
[/code]
--------------------------------------------
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
--------------------------------------
起线程异步调用
[code="java"]ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(() -> behaviorLogService.insertLoginLog(behaviorLog));
//new Thread(() -> behaviorLogService.insertLoginLog(behaviorLog));[/code]
--------------------------------------
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
[code="java"]
public static InetAddress getLocalHost() {
Enumeration<NetworkInterface> netInterfaces = null;
try {
netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
NetworkInterface ni = netInterfaces.nextElement();
Enumeration<InetAddress> 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;
}
[/code]
-----------------------------------
springMVC 学习
1, 创建maven项目, 选择webapp的archetype
2, JSP中用${error}来获取model中的值
3, 在web.xml中用DispatcherServlet来取代原来的ContextLoaderListener
4, DispatcherServlet 对应的xml中,只需要一个<context:component-scan/> 就ok
5, 拦截器 loginInterceptor 某些路径不需要拦截(/api,/static等). [房源]
6, 异常处理 @ExceptionHandler BaseController
7, 视图解析器
return "/WEB-INF/jsp/"+pageName+".jsp" 变成了 return pageName;
8, <!-- 支持异步方法 / 支持定时任务-->
<task:annotation-driven/>
-----------------------------------
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
[code="java"]
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();
[/code]
-----------------------------------------
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
[code="java"]
IdentityHashMap<Integer, Integer> imap = new IdentityHashMap<Integer, Integer>();
int a = 127;
imap.put(a, 5);
imap.put(a, 6);
imap.put(a, 7);
System.out.println(imap.size());
[/code]
---------------------------------------
server端返回的数据都是string的, 即使声明成integer的话, 客户端也转不了.
服务端
[code="java"]
@Override
public ResponseEntity<?> microChatData2(String param, String startDate, String endDate) {
List<Integer> list = behaviorLogService.microChatData2(param, startDate, endDate);
return ResponseEntity.ok(list);
}
[/code]
客户端
[code="java"]
List<Integer> result = RestClient.exchange(url,HttpMethod.GET,List.class);
for (Integer r : result) {
syso;
}
[/code]
---------------------------------------
除法百分比
[code="java"]
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) +"%");
[/code]
-------------------------------------
springMVC服务端如果是直接return个json对象, 用chrome或是api的方式 得到的是一个xml的对象.
需要将json对象转成string的
return ResponseEntity.ok(json.toString());
-------------------------------------------
Map 按照key倒排
[code="java"]
String result = RestClient.exchange("http://localhost:9600/oms/v1/microChatData?param="+param,HttpMethod.GET,String.class);
Map<String,Integer> map = (Map<String, Integer>) JSONObject.parse(result);
TreeMap<String,Integer> treeMap = new TreeMap<String,Integer>(map);
for (String key : treeMap.descendingKeySet()) {
System.out.println(key +" " + treeMap.get(key));
}
[/code]
-----------------------------------
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 的方式来做
[code="java"]
<update id="batchUpdate" parameterType="map">
update a set a.remark = #{remark}, a.updateTime = getDate(), readStatus = 1
from t_message_last a
inner join (
<foreach collection="userCodeSet" item="userCode" separator=" union all " open="(" close=")">
select #{appId} as appId, #{businessId} as businessId, #{userCode} as userCode
</foreach>
) b on a.userCode = b.userCode and a.appId = b.appId and a.businessId = b.businessId
</update>
<insert id="batchInsert" parameterType="map">
insert into t_message_last(appId, businessId, userCode, businessName, remark, createTime, readStatus)
select a.*,#{businessName}, #{remark} , getDate(), 1
from (
<foreach collection="userCodeSet" item="userCode" separator=" union all " open="(" close=")">
select #{appId} as appId, #{businessId} as businessId, #{userCode} as userCode
</foreach>
) a
where not exists ( select 1 from t_message_last c where c.userCode =a.userCode and c.appId = #{appId} and c.businessId = #{businessId} );
</insert>
[/code]
----------------------
secureCRT有时在session中设置的编码没有效果, 在需要堡垒机跳转的情况
需要在global中设置
[img]http://dl2.iteye.com/upload/attachment/0115/5333/459e45de-a5e3-30fb-8ce2-64016850d565.png[/img]
-----------------------------------
rz sz 命令可以在secureCRT中上传下载文件
--------------------------
[code="java"]
String[] ss = {"a","b","c"};
List<String> asList = Arrays.asList(ss);
asList.remove("a");
[/code]
这里会报错, Arrays.asList 出来的List没有实现remove方法.
可以用下列方式
[code="java"]
String[] s = {"a","b","c"};
List<String> list2 = new LinkedList<String>();
Collections.addAll(list2, s);
list2.remove("a");
System.out.println(list2.size());
[/code]
-----------------------------
ArrayList 和 LinkedList
LinkedList删除的速度比ArrayList快
----------------------------------
delete 和 insert写在一起
[code="java"]
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 < ?
[/code]
------------------------------
left join on where
1. 对于left join,不管on后面跟什么条件,左表的数据全部查出来,因此要想过滤需把条件放到where后面
2. 对于inner join,满足on后面的条件表的数据才能查出,可以起到过滤作用。也可以把条件放到where后面。
[code="java"]
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;
[/code]
------------------
transient
某些不需要传给客户端的属性可以用transient来屏蔽掉
transient private String userCode;
------------------
泛型使用
[code="java"]
public class Pagination<T> {
private List<T> list;
}
[/code]
--------------
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 = ""; 就没有问题
0 0
- 2016
- 2016
- 2016
- 2016!
- 2016
- 2016
- 2016
- 2016
- 2016
- 2016
- 2016
- 2016
- 2016
- 2016-
- 2016
- 2016
- 2016
- 2016
- Mybatis中如何在SQL语句表名中使用参数
- Mac下配置XAMPP+EclipsePHP
- IOS实战 (4) 之 仿微信新闻评论框+ 半透明模糊效果
- POJ 3061 Subsequence 【尺取法】
- 在苹果做了十年公关,我总结了这五条建议
- 2016
- spring@Transactional注解解决事务处理问题
- 3Sum
- 使用Python实现Map Reduce程序
- PSR规范
- [林轩田]14-规范化
- HDU 1565 方格取数(1) (状压DP)
- Redis内部数据结构详解之字典(dict)
- profile perf性能检测工具