Sunshow Life

Beyond


  • 首页

  • 归档

  • 标签

[Spring+Hibernate]小心处理脏数据的自动更新

发表于 2010-09-14 | 分类于 Java

有并发请求的时候会存在这种隐患
例如请求A和B都是同一个Action的实例,并取了同样的数据做处理
A–>取数据–>调用set方法设置A相关的数据–>(B处理数据的时间点)–>页面展现
B–>取数据–>调用set方法设置B相关的数据–>页面展现

也就是说在A设置完数据到页面展现的中间这个时间段里B又把同样的数据设置成了其他的值
这时候Spring的事务管理就会检测数据的一致性,如果发现有不一致的就做自动更新

解决方法有几种:

  1. Action里不对数据进行处理
    比如我碰到的情况时间原因就把不同的处理放到JS去处理了
  2. 自己管理事务,不使用Spring的事务管理
  3. 实现数据对象的Clone方法,页面展现使用的数据都通过Clone脱离和Spring管理的数据库session的关系

由于我没有对Spring和Hibernate做过深入研究,以上分析仅为猜测,谢绝拍砖
不过这个问题确实是存在的,解决方法也是有效的,也从另一个角度说明要想驾驭框架就得掌握其处理机制

Tomcat支持SSI和软链接

发表于 2010-07-21 | 分类于 Java

一. 启用SSI(Server Side Include)

  1. 编辑Tomcat的web.xml,查找SSI,去掉相应的servlet和servlet-mapping的注释,或者也可以去掉filter的,二选一
  2. 给相应的Context添加privileged=”true”属性

点评:不知道这个SSI有毛用,直接jsp:include多好,而且一启用这个就影响所有的Context

二. 允许软链接

给相应的Context添加allowLinking=”true”属性

[Expression Engine]去除URL里的index.php

发表于 2010-06-17 | 分类于 PHP
  1. 配置url rewrite
    编辑根目录下的.htaccess文件,没有就新建一个,内容如下:

    1
    2
    3
    4
    5
    6
    7
    <IfModule mod_rewrite.c>
    RewriteEngine On
    #RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
    </IfModule>
  2. 配置EE链接生成规则

CP Home › Admin › System Preferences › General Configuration

把Name of your site’s index page这一项删掉留空

工作经验总结

发表于 2010-06-14 | 分类于 Life

一转眼,我竟然也工作满五年了,真是不可思议
我得说,工作教会了我很多东西,尤其是最近两年的经验
于是恬着脸总结一下

  • 技术不是最重要的,产品为王

    从刚开始工作,就有人告诉我技术不是最重要的,不过很显然那时候的我并不能深刻认识到这一点。在一家以产品为自己目标的公司,往往对产品的良好包装能带来更大的效益,当然这并不是在藐视技术,技术是根本,只不过很多技术起家的公司往往会忽略了技术以外的东西

  • 多关注其他人在做什么,勇于担当

    在一个公司或者一个团队,仅仅做好自己手头的事是不够的,多关注其他人在做什么,关注自己参与的项目中整个项目是怎么工作的,对团队对自己都才能更有好处。我认识不少的人,有的除了自己做的东西以外一问三不知,有的照猫画虎做了很长一段时间也不去思考为什么应该这么做。不知道一些事情很正常,不知道还不愿意去了解,甚至还排斥就不好了。
    对于刚进入公司或团队的新人,往往会面临没人搭理或者无事可干的情况,这一点就尤其重要

  • 对别人宽容一些,沟通很重要

    很多所谓技术人员都有这种鄙视别人的臭毛病,比如我也是。
    在找人做事的时候自己感觉一清二楚的事情,为什么讲了好几遍别人还不明白,或者很简单的事情做了很多天还漏洞百出?这时候就需要好好想想了,我自己的理解是,给别人描述的时候多站在对方的立场,考虑对方的知识面和专业领域,通俗点说就是见人说人话,见鬼说鬼话。
    很多人都会有这种经验,一个问题交给别人做,结果给人讲解的时间自己都能做完了,还不如自己做了呢。如果什么都自己做,只会把自己搞得越来越累,而且让其他人感觉不到信任感,其实每个人都各有各的长处,沟通的成本本身也不可避免,只要沟通方式合理,大部分的事情都是可以做好的

[WordPress]对不同域名使用不同的主题

发表于 2010-04-28 | 分类于 WordPress

首先是让WordPress能支持多个域名而不是跳转到安装时指定的域名

编辑wp-config.php,加上:

1
2
3
4
$home = 'http://'.$_SERVER['HTTP_HOST'];
$siteurl = 'http://'.$_SERVER['HTTP_HOST'];
define('WP_HOME', $home);
define('WP_SITEURL', $siteurl);

然后针对不同域名指定不同的主题,本来想自己写一个,然后犯懒一搜果然已经有人做了

安装插件Domain Theme,激活然后设置就不赘述了

libcurl与CLOSE_WAIT

发表于 2010-03-02 | 分类于 C

调用libcurl下载,然后使用netstat查看发现有大量的TCP连接保持在CLOSE_WAIT状态
查看libcurl的文档说明,有这样一个选项:

CURLOPT_FORBID_REUSE

Pass a long. Set to 1 to make the next transfer explicitly close the connection when done. Normally, libcurl keeps all connections alive when done with one transfer in case a succeeding one follows that can re-use them. This option should be used with caution and only if you understand what it does. Set to 0 to have libcurl keep the connection open for possible later re-use (default behavior).

也就是说,默认情况下libcurl完成一个任务以后,出于重用连接的考虑不会马上关闭
如果没有新的TCP请求来重用这个连接,那么只能等到CLOSE_WAIT超时,这个时间默认在7200秒甚至更高,太多的CLOSE_WAIT连接会导致性能问题

解决方法:

1
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);

最好再修改一下TCP参数调低CLOSE_WAIT和TIME_WAIT的超时时间

查看RPM包信息

发表于 2010-01-28 | 分类于 Linux

查看包名:

1
rpm -q --queryformat="%{NAME}\n" -p foo.rpm

查看版本号:

1
rpm -q --queryformat="%{VERSION}\n" -p foo.rpm

查看更多可用属性

url的encode和decode

发表于 2009-11-14 | 分类于 C

相关RFC:http://curl.haxx.se/rfc/rfc2396.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/* ---------------------------------------------------------------------------
* Encode URL by converting special characters to %XX (where XX are hexadecimal digits)
* Don't forget to free the return value.
*/
char *urlencode(const char *url)
{
#define COPY_TO_ENCODE_URL(c) \
if (outlen < pos) { \
outlen += 10; \
out = realloc(out, outlen + 1); \
} \
out[pos ++] = c; \
size_t i, len = strlen(url), outlen;
outlen = len;
char *out = malloc(outlen + 1);
int pos;
for (i = 0, pos = 0; i < len; i ++) {
if ((url[i] >= 48 && url[i] <= 57) // 0-9
|| (url[i] >= 65 && url[i] <= 90) //a-z
|| (url[i] >= 97 && url[i] <= 122) //A-Z
|| url[i] == ';' || url[i] == '/' || url[i] == '?'
|| url[i] == ':' || url[i] == '@' || url[i] == '&'
|| url[i] == '=' || url[i] == '+' || url[i] == '$'
|| url[i] == ',' || url[i] == '-' || url[i] == '_'
|| url[i] == '.' || url[i] == '!' || url[i] == '~'
|| url[i] == '*' || url[i] == '\'' || url[i] == '('
|| url[i] == ')') {
/* straight copy */
COPY_TO_ENCODE_URL(url[i]);
}
else {
#undef HEX_TO_DIGIT
char dig1 = (url[i] & 0xF0) >> 4;
char dig2 = (url[i] & 0x0F);
if (dig1 >= 0 && dig1 <= 9) dig1 += 48; //0,48inascii
if (dig1 >= 10 && dig1 <= 15) dig1 += 65 - 10; //A,65inascii
if (dig2 >= 0 && dig2 <= 9) dig2 += 48;
if (dig2 >= 10 && dig2 <= 15) dig2 += 65 - 10;
COPY_TO_ENCODE_URL('%');
COPY_TO_ENCODE_URL(dig1);
COPY_TO_ENCODE_URL(dig2);
}
}
out[pos] = '\0';
return (out);
}
/* ---------------------------------------------------------------------------
* Decode URL by converting %XX (where XX are hexadecimal digits) to the
* character it represents. Don't forget to free the return value.
*/
char *urldecode(const char *url)
{
size_t i, len = strlen(url);
char *out = malloc(len + 1);
int pos;
for (i = 0, pos = 0; i < len; i ++) {
if (url[i] == '%' && i+2 < len &&
isxdigit(url[i + 1]) && isxdigit(url[i + 2])) {
/* decode %XX */
#define HEX_TO_DIGIT(hex) ( \
((hex) >= 'A' && (hex) <= 'F') ? ((hex) - 'A' + 10): \
((hex) >= 'a' && (hex) <= 'f') ? ((hex) - 'a' + 10): \
((hex) - '0') )
out[pos ++] = HEX_TO_DIGIT(url[i + 1]) * 16 +
HEX_TO_DIGIT(url[i + 2]);
i += 2;
#undef HEX_TO_DIGIT
}
else {
/* straight copy */
out[pos ++] = url[i];
}
}
out[pos] = '\0';
return (out);
}

[Socket]获取客户端IP

发表于 2009-07-16 | 分类于 C

有两种方法,一种是在accept的时候获取,一种是通过getpeername获取

1
2
3
4
5
6
7
#include <sys/socket.h>
int accept(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);
int getpeername(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);

两者区别主要在取IP的fd不一样,前者是在监听的fd,后者是在连接建立的fd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct sockaddr_in addr;
socklen_t addr_len;
int32_t listen_fd, sock_fd;
/* create listening port */
addr_len = sizeof(addr);
memset(&addr, 0, addr_len);
sock_fd = accept(listen_fd, (struct sockaddr *)&addr, &addr_len);
printf("%d\n", addr.sin_addr.s_addr);
memset(&addr, 0, addr_len);
getpeername(sock_fd, (struct sockaddr *)&addr, &addr_len);
printf("%d\n", addr.sin_addr.s_addr);

当然这种长整型格式的IP不一定是我们想要的,可以通过inet_ntoa转换

1
2
3
4
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);
1
printf("%s\n", inet_ntoa(addr));

Curl上传文件

发表于 2009-06-29 | 分类于 Network
1
curl -H "Expect:" -F "action=upload_mf.php" -F "file=@1246285971.xml;type=text/xml" http://localhost/upload_mf.php

加上”Expect:”的Header是因为Curl会默认带上”Expect: 100-continue”,而我用的lighttpd 1.4.18不支持这个Header,会返回417的状态码导致出错

12345
Sunshow

Sunshow

Beyond the Life

50 日志
12 分类
122 标签
RSS
© 2017 Sunshow
由 Hexo 强力驱动
主题 - NexT.Pisces