#
这几天抽空把How tomcat works看了一遍。
这本书写得很好,把tomcat这么一个牛B的大家伙拆成一堆零件,然后告诉你怎么组装,真是做到了掰开了揉碎了讲。
简单记一下
第一章讲web服务器,如何接受和响应http请求,还举了个sokcet的例子。算是入门,从很底层的技术讲起。
第二章讲servlet容器,javax.servlet.Servle接口,接受到http请求后如何查找servlet,执行servlet。
第三章讲连接器的概念,前两章看下来你会觉得把http请求接受响应跟容器放在一起太乱了,这章就讲如何把http操作提出来作为一个连接器。
第四章讲tomcat默认连接器,http协议操作讲得很详细,不过我没怎么看哈,用的时候直接把tomcat这段代码拿过来就是了。
第五章讲容器,在第三章的基础上对容器进行分层分类,事情复杂了就分成几部分,“治众如治寡,分数是也”这个我们都知道。
tomcat讲容器分成这几个概念:
Engine:表示整个Catalina的servlet引擎
Host:表示一个拥有数个上下文的虚拟主机
Context:表示一个Web应用,一个context包含一个或多个wrapper
Wrapper:表示一个独立的servlet
类型复杂了,要做的事情也复杂了。
不仅仅是执行service()方法,还要前边执行一堆,后边再来一堆。引入了流水线任务Pipelining Tasks的概念,在流水线上可以执行多个Valve(有翻译成阀),类似于拦截器的概念。
第六章讲生命周期,人多了要讲究个步调统一,引入了Lifecycle接口的概念,方法包括启动之前干什么、启动之后干什么、启动后把子容器也启动了。
包括引入监听接口,都是些java常见实现方式,没什么特殊。
第七章讲日志系统,没看。
第八章讲加载器,可以参考
tomcat类加载器及jar包冲突问题分析 http://www.blogjava.net/zyskm/archive/2011/12/06/365653.html 就不重复了。
第九章讲session管理,没什么特别的。
第十章讲安全,没看。
第十一章讲StandardWrapper,在第五章的基础上重点分析了wrapper的运作机制。
其余章节目前工作中用不到,有空再看了。
作者:zyskm
http://www.blogjava.net/zyskm
上一篇说明了一种spring事务配置方式,这次补上另一种。
见配置文件:
<!-- 事务拦截 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="search*" propagation="REQUIRED" read-only="true" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="send*" propagation="REQUIRED" />
<tx:method name="revoke*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="logging*" propagation="NOT_SUPPORTED" read-only="true" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="projectServiceOperation" expression="execution(* cn.ceopen.bss..*.service..*(..))" />
<aop:advisor pointcut-ref="projectServiceOperation" advice-ref="txAdvice" />
</aop:config>重点说明两点:
1.<aop:pointcut id="projectServiceOperation" expression="execution(* cn.ceopen.bss..*.service..*(..))" />
表示你要进行事务控制的类名。详细资料可以查下 aspectj语法。
配置完成一定要实际测试一下,我配置过 expression="execution(* cn.ceopen.bss..*.service.*(..))" 少了一个点,导致事务不起作用。
导致项目很长一段时间事务方面没经过严格测试。
2.
Spring的AOP事务管理默认是针对unchecked exception回滚。
也就是默认对RuntimeException()异常极其子类进行事务回滚。
在项目中定义公共的RuntimeException异常,避免每个开发人员随意抛出异常。
不然的话没新定义一个异常,就要修改tx:method rollback-for 太麻烦了。
总结:
1.对事务配置进行检查,对复杂嵌套的事务逻辑必要的时候debug到spring源码中确认。
2.定义统一异常类型
3.同一个类调用自身方法,子方法的事务配置不起作用。解决方法见上一篇文章。
http://www.blogjava.net/zyskm/archive/2011/11/11/363535.html作者: zyskm
本文地址:
http://www.blogjava.net/zyskm/archive/2011/11/30/365225.html
在开发中缓存是经常要用到的,什么东西都一遍遍的找数据库问,数据库表示压力很大。
缓存方案常见的有两种,一种是在客户端,也就是web开发中的浏览器。一种是在服务器端,以memcached为代表。
浏览器缓存
这几天因为项目需了解了下浏览器缓存相关的知识。
重点说一下HTML5 Storage技术,之前的那些技术都是浮云,存不了什么东西还贼难用,各浏览器不兼容。
听名字就知道这是这两年刚出来的技术,相应的也就对浏览器版本要求比较高,低版本的浏览器不支持。对用公司内部用的话这个技术还是很不错的。
最多支持5M的容量,是个xml文件,备注:
Html5 storage最大支持5M容量
文件位置,根据系统用户位置会有区别。
C:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Internet Explorer\DOMStore\KF2G0R0O
也就是说别人都能看到你的数据,所以不能存放需要保密的内容。
每次用户登录的时候最好检查一下缓存版本是否跟服务器一致。
现在的项目中有个业务受理环节,设置的过程中需要大量使用一些基础数据。类似分公司、部门、产品列表这类数据,不经常变动,反复到服务器请求的话对服务器来讲是不小的压力。
业务受理的步骤很多,得点好几个下一步才能把操作完成,半截数据放到数据库里维护起来结构就复杂了。
因此考虑采用本地缓存技术,比较来比较去HTML5 Storage是不错的选择,反正都是公司同事可以要求都使用IE8以上浏览器。
下边这段是js中用到的代码
//用jquery方式,为加载缓存到本地按钮绑定方法

$('#loadBtn').bind('click',function(event)
{

if(supports_html5_storage())
{
localStorage.clear();
load();
alert("数据已经缓存到本地!");
initCorpSelect();
initDptSelect("-1");

}else
{
alert("You're out!");
}
}) ;
//清空缓存

$('#clearBtn').bind('click',function(event)
{

if(supports_html5_storage())
{
localStorage.clear();
alert("本地缓存已经清空!");
initCorpSelect();
initDptSelect("-1");

}else
{
alert("You're out!");
}
}) ;
//加载缓存到本地浏览器

function load()
{

var params =
{
url:"${ctx}/crm/product/product/webstorage!ajaxLoad.do",
type: "post",
dataType: "json",
data: null,

success: function(response)
{
var corps = response.corps;
var dpts = response.dpts;
var stations = response.stations;


for(var i=0;i<corps.length;i++)
{
var corp = corps[i];
var jsCorp = new Corp(corp.corpCode,corp.corpName);
localStorage.setItem("corp."+corp.corpCode, jsCorp.toJSONString());
}


for(var i=0;i<dpts.length;i++)
{
var dpt = dpts[i];
localStorage.setItem("dpt."+dpt.dptCode, dpt.toJSONString());
}


for(var i=0;i<stations.length;i++)
{
var station = stations[i];
localStorage.setItem("station."+station.stationCode, station.toJSONString());
}
}
};
ajax(params);
}
服务器缓存
缓存解决方案很多了,只说刚刚用到的memcached。
memcached很好用了
1.安装启动memcached
2.写一个memcached客户端工具类,我用的是com.danga.MemCached.MemCachedClient 比较稳定,至于其他性能更高的目前没有需求没用到。
3.加载数据到memcached
4.程序中需要基础数据的时候从memcached获取。

/** *//**
* memcached接口
* @author ce
*
*/

public interface Imemcached
{

/** *//**
* 可增加,可覆盖
*/
public abstract boolean set(Object key, Object value);
public abstract boolean set(Object key, Object value,Date expire);

/** *//**
* 只能增加;如果增加的key存在返回“false”
*/
public abstract boolean add(Object key, Object value);
public abstract boolean add(Object key, Object value,Date expire);

public abstract boolean delete(Object key);


/** *//**
* 只能修改;如果修改不存在的key返回“false”
*/
public abstract boolean modify(Object key, Object value);


/** *//**
* 如果key不存在返回null
*/
public abstract Object getKey(Object key);


/** *//**
* 清除服务器上所有数据
*/
public abstract boolean flushAll();


/** *//**
* 判断服务器上是否存在key
*/
public abstract boolean keyExists(Object key);


/** *//**
* 一次获取多个数据,减少网络传输时间
*/
public abstract Map<String, Object> getKeys(String[] keys);

/** *//**
* 设置是否使用字符串方式
*/
public abstract void setPrimitiveAsString(boolean flag);
}
实际测试结果
查询一张人员表,同时需要根据分公司编号,部门编号从分公司、部门表获取名称。
使用缓存技术的时候,不管客户端还是服务器端,因为只查询单表,速度明显比多表联合查询要快的多。
在系统使用高峰的时候这种差别明显能改善用户的操作体验。
实际测试了以下几种情况:
1.查询:
直接通过表关联的方式进行查询,速度最慢,开发最简便
查询结果列表中的公司名称、部门名称直接从数据库查出。
2.查询(本地缓存),缓存数据到本地,清除本地缓存:
速度最快,数据同步有一定工作量,需要高版本浏览器支持
查询结果列表中的公司名称、部门名称从本地缓存获取,增加_IE标识以区别。
3.查询(服务器缓存),缓存数据到服务器,清除服务器缓存:
速度也很快,也有数据同步问题,缓存数据到服务器比本地慢
查询结果列表中的公司名称、部门名称从服务器缓存获取,增加_mem标识以区别。

缓存使用总结
1.采用缓存技术后系统性能有明显改善,可以从性能测试工具明显感受到(这不是废话嘛,呵呵)。
2.缓存的数据同步问题必须解决好
3.项目中采用缓存技术需要统一规划,各系统不能互相干扰。
4.性能压力不明显的情况下,缓存开发要显得复杂一点。
作者: zyskm
本文地址:
http://www.blogjava.net/zyskm/archive/2011/11/30/364722.html
声明性事务是spring一个很重要的功能,可以避免开发陷入繁琐的事务控制逻辑中。
但是可能是用着太方便了很多人对spring事务原理并不清楚,有必要做一番分析。
下边以拦截器配置方式进行说明,tx标签配置方式将在接下来另一篇文章做分析。
一、首先看配置文件:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="matchAllTxInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
<prop key="search*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
<prop key="save*">PROPAGATION_REQUIRED,-Exception </prop>
<prop key="modify*">PROPAGATION_REQUIRED,-Exception </prop>
<prop key="send*">PROPAGATION_REQUIRED,-Exception </prop>
<prop key="revoke*">PROPAGATION_REQUIRED,-Exception </prop>
<prop key="del*">PROPAGATION_REQUIRED,-Exception </prop>
<prop key="logging*">PROPAGATION_NOT_SUPPORTED,readOnly,-Exception </prop>
<prop key="*">PROPAGATION_SUPPORTS,-Exception </prop>
</props>
</property>
</bean>
<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list><idref local="matchAllTxInterceptor" /></list>
</property>
<property name="proxyTargetClass"><value>true</value></property>
<property name="beanNames">
<list><value>*Service</value></list>
</property>
</bean>配置第一步引入AOP代理autoProxyCreator,使用的是spring默认的jdk动态代理BeanNameAutoProxyCreator。
有两个属性要介绍一下:
1.拦截范围beanNames;例子中拦截范围是*Service,表示IOC容器中以Service结尾的bean,一般配置在spring.xml,serviceContext.xml之类的spring配置文件。
要注意这里不是值src下边的类。
bean配置信息:
<bean id="menuService" class="cn.ceopen.bss
..service.impl.MenuServiceImpl"/>有图有真相,下边是BeanNameAutoProxyCreator 调试信息。


2.截器interceptorNames
interceptorNames定义事务属性和事务管理器
配置第二步就是定义事务属性:事务传播范围、事务隔离级别
事务属性没什么好说的,使用spring进行事务管理的都了解,不在这里详细说了网上有大量资料。
配置第三步,指定事务管理器
这里用的是HibernateTransactionManager,spring提供对常见orm的事务支持。从spring源码可以看出HibernateTransactionManager.doGetTransaction()同时支持hibernate和jdbc。
支持hibernate和jdbc混合事务,不使用jta方式的话有个前提条件:使用同一个数据源,
这里所说的同一个数据源,不仅仅指物理上是同一个,在spring配置文件中也要是同一个。
我在开发中遇到过这个问题,最早定义了一个数据baseDataSource,hibernate和jdbc都使用此数据源,后来项目要求使用动态数据源就又配了一个数据源dynamicDataSource
仅在hibernate下做了改动,未改动jdbc对应配置,出现了事务控制问题。
出错了事务配置:
<bean id="sessionFactory"
class="com.sitechasia.webx.dao.hibernate3.NamedMoudleHbmLocalSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource" />
<!--与主题无关,省略部分内容-->
</bean>
<bean id="dynamicDataSource" class="cn.ceopen.bss.pub.base.dao.RoutingDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="baseDataSource" value-ref="baseDataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="baseDataSource"/>
</bean>
<bean id="baseDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<!--与主题无关,省略部分内容-->
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--dataSource应该与sessionFactor一致-->
<property name="dataSource"><ref bean="baseDataSource"/></property>
</bean>
<bean id="abstractJdbcDao" abstract="true">
<property name="jdbc" ref="jdbcTemplate" />
</bean>dao配置文件:
<bean id="actDao" class="cn.ceopen.bss
.impl.ActDaoImpl" parent="abstractJdbcDao"/>dao中同时支持hibernate操作和jdbc操作。
二、事务属性传播
先看这样一个列子:

1.基于jdk动态代理的AOP事务控制,只能针对接口。
在上边的配置文件中设置的事务属性对a3()都不起作用,a3()不能单独设计事务属性,只能继承接口方法的事务属性。
2.类自身事务嵌套
第一种情况:
AbcIService abcService;
BcdIService bcdService;
abcService.a1();
abcService.a2();
bcdService.b1();
这三个方法对应的事务属性都起作用。
第二种情况:
方法定义
public void a1() {
bcdService.b1();
}
调用:
abcService.a1();
结果:
abcService.a1();
bcdService.b1();
这两个方法对应的事务属性都起作用。
第三种情况:
方法定义
public void a1() {
this.a2();
}
调用:
abcService.a1();
结果:
abcService.a1();
abcService.a2();
a2()对应的事务属性配置不起作用。
解决办法:
1.把a2()拆到另一个类中去;
缺点:麻烦,会把相关业务逻辑拆分了
2.调用是不用this.a2(),用abcService.a2();
public void a1() {
abcService.a2();
}
缺点:要在类中注入自身引用。
原因分析:
为什么会出现这种情况呢?
我们在调用abcService.a1();时abcService是从IOC容器获取的,并AbcServiceImpl而是它的动态代理AbcServiceProxy。
示意图如下,spring不一定是这么实现的但原理一样.

AbcServiceProxy.a()方法进行了AOP增强,根据配置文件中事务属性增加了事务控制。
public void a1() {
this.a2();
}
this.a2()这里this指的是AbcIServiceImpl并没用进行AOP增强,所以没用应用事务属性,只能继承a1()的事务属性。
public void a1() {
abcService.a2();
}
abcService则实际是AbcServiceProxy.a2()所以可以应用事务属性。
所以在类内部进行方法嵌套调用,如果被嵌套的方法a2()需要区别于嵌套方法a1()的事务属性,需要:1.在接口公开;2.通过代理调用。
作者:zyskm
http://www.blogjava.net/zyskm
上周在西单图书城看到本不错的书<<七步掌握业务分析>>,系统的讲了些业务分析方面的知识,以前看到业务分析方面的资料都是站在需求捕获分析的角度来写,向这么完整系统介绍业务分析概念方法的不多。本着书非借不能读的精神,我用了两个周末在西单图书大厦看完了整本书。记录一下阅读感受,同时结合一些自己的理解。
目录结构见下图,大概是这个意思,名词记得不是很准确。

一个个说一下。
1.什么是业务分析
一般来讲"什么是...?"这种问题都可以细分为这几个问题,什么是业务分析、业务分析做什么(工作范围)、跟系统分析有什么区别、什么人能做业务分析。
让大家明白组织是怎么运作的,为了实现组织的目标提供解决方案。
实际开发过程中谁都可以做业务分析工作,目前很少看到这门业务分析师这一角色,一般是需求和系统分析师主要来做。根据个人能力的不同介入的程度不同。
说到范围,业务分析主要从业务需求的角度来考虑,区别于系统分析更多的从系统能否实现、怎么实现的角度来考虑。很多时候系统分析师是同时兼这两个角色的,优势是考虑问题有统一方向,缺点的是容易互相干扰。通用的解决思路是颜色帽子法,做哪块工作时戴那个帽子只想这部分的事情,先不想别的部分怎么办,先过今天再说明天。每一部分单独考虑后再进行综合考虑,这样工作才好开展,要不然一次想太多了事情就变得太复杂。
2.什么人来做
有人的地方就有江湖,既然在江湖里混就要了解这个江湖是什么人组成的,每个人的立场、对事情的认识程度、角色、权利、影响。对这些人有了认识,才能更好的认识人做的事情。
这一点一般的需求书上只是提了一下,不想这本书就组织架构、角色关系、沟通技巧各方面做了阐述。有个理论认识实际操作起来更容易有方向感。
3.项目做什么
很多开发人员经常是领导让做什么就做什么,作为一个业务分析师显然不能这么干。
业务分析师很多时候起的是一个导游的角色,探险的时候大家全两眼一抹黑只能掉沟里了。
谁发起的项目,项目要达成什么目标,对哪些人有益,对哪些人不利。这些都要了解,在项目的过程中才知道从哪方面去推动,避开可能会引起的麻烦。
4.了解业务
这个是当然了,业务分析师嘛,具体方法先不写了,都是写常见的,重要的是要经常实际总结提高。
5.了解业务环境
这也是一个江湖,更多的是从事情的角度进行分类
6.了解技术环境
业务分析虽然不用写代码技术还是要懂一点的,好的服装设计师都会自己做衣服(这可不是随便说的,我见过几个,呵呵)。
7.提升自身价值
洞悉事态,能够提出完整解决方案,这样的人当然是有价值的。做得越好越有价值。
书中提到了几种提高技能方法:时间管理和一些分析技术,包括沟通技巧。
先写这么多。
作者:zyskm
http://www.blogjava.net/zyskm
基于spring的动态数据源
项目过程中遇到这样一个需求,系统启动后动态设置数据源,不同用户登录系统后访问的数据库不同。
好在所有书库结构一致。
用spring 的AbstractRoutingDataSource解决了这个问题。
原理如图:

项目采用的是hibernate,直接在spring.xml设置sessionFactory的dataSource属性为动态数据源即可。
因为项目所有数据库结构都一致,为了避免每次设置数据源的时候要改一堆参数,修改了spring AbstractRoutingDataSource类增加了一个getTargetDataSources方法,获取当前数据源详细信息,在其基础上修改数据库名称、用户名、密码即可,不用每次设置一堆参数。
Map<String,ComboPooledDataSource> targetDataSources=dynamicDataSource.getTargetDataSources();

if(targetDataSources==null)
{
targetDataSources=new HashMap<String, ComboPooledDataSource>();
targetDataSources.put("baseDataSource", baseDataSource);
}
targetDataSources.put(dataSourceName, subSystemDataSource);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.afterPropertiesSet();另外,设置AbstractRoutingDataSource参数后要调用afterPropertiesSet()方法,spring容器才会进行加载操作。
在动态设置数据源方面,可以通过两种方式实现:
1.在action(项目使用struts)中进行设置,可以确保在每个servlet线程中数据源是一致的。
2.以aop方式,对service方法进行拦截,根据需求设置不同数据源。
在开发过程中数据库的操作和使用要有一定规范,不然会引起混乱。
下边是我们开发中具体例子,因为涉及公司在用项目详细代码就不列出来了,整个思路可供参考。
1.初始化脚本
各子系统建立自己的数据库初始化脚本,格式可参照附件产品管理初始化脚本sql.rar(需要解压到c:/sql才能在命令行执行,见init.sql说明)
包括两部分内容:1.建表语句(ddl);2.基础数据初始化(data)
建表语句由数据库设计文档(PowerDesigner)导出,基础数据由excel文件导出(sql.rar提供示例,开发框架提供工具支持DbUtilTest.testExcel2Sql ())
作用:
1.数据库结构和基础数据文档化
2.便于快速搭建开发测试环境,新建一套环境时不用拷贝原数据库而是执行脚本
3.便于独立开发测试,有一个干净的数据,避免开发测试依赖历史数据和调试过程中互相影响
2.数据库结构比对
在部署多套数据库时,怀疑表结构不一致,可使用DbUtilTest.testCompareDataBase ()进行检查。
执行后会在子系统根目录生成dbcompare.html 文件,参加附件。
说明:红色表示两个表结构不一致,绿色表示多出一表,黑色表示一致
3.数据库字符集(UTF-8)
create database dbname CHARACTER SET utf8 COLLATE utf8_bin
不单独对表和字段设置字符集,整个库统一使用utf-8
4.表名字段名
建库脚本中表名和字段名不区分大小写
5.数据库引擎(InnoDb)
目前主要使用的两种引擎MyIsam,InnoDb。MyIsam查询较快,不支持事务。InnoDb支持事务。
在建表sql指明引擎。
create table ***
(
id bigint(11) not null auto_increment,
.........
primary key (id)
)
type = innodb;
powerdesiner按如下方式设置:
字符集的概念大家都清楚,校对规则很多人不了解,一般数据库开发中也用不到这个概念,mysql在这方便貌似很先进,大概介绍一下。
简要说明
字符集和校对规则
字符集是一套符号和编码。校对规则是在字符集内用于比较字符的一套规则。
MySql在collation提供较强的支持,oracel在这方面没查到相应的资料。
不同字符集有不同的校对规则,命名约定:以其相关的字符集名开始,通常包括一个语言名,并且以_ci(大小写不敏感)、_cs(大小写敏感)或_bin(二元)结束
校对规则一般分为两类:
binary collation,二元法,直接比较字符的编码,可以认为是区分大小写的,因为字符集中'A'和'a'的编码显然不同。
字符集_语言名,utf8默认校对规则是utf8_general_ci
mysql字符集和校对规则有4个级别的默认设置:服务器级、数据库级、表级和连接级。
具体来说,我们系统使用的是utf8字符集,如果使用utf8_bin校对规则执行sql查询时区分大小写,使用utf8_general_ci 不区分大小写。不要使用utf8_unicode_ci。
如create database demo CHARACTER SET utf8; 默认校对规则是utf8_general_ci 。
Unicode与UTF8
Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储.
UTF8字符集是存储Unicode数据的一种可选方法。 mysql同时支持另一种实现ucs2。
详细说明
字符集(charset):是一套符号和编码。
校对规则(collation):是在字符集内用于比较字符的一套规则,比如定义'A'<'B'这样的关系的规则。不同collation可以实现不同的比较规则,如'A'='a'在有的规则中成立,而有的不成立;进而说,就是有的规则区分大小写,而有的无视。
每个字符集有一个或多个校对规则,并且每个校对规则只能属于一个字符集。
binary collation,二元法,直接比较字符的编码,可以认为是区分大小写的,因为字符集中'A'和'a'的编码显然不同。除此以外,还有更加复杂的比较规则,这些规则在简单的二元法之上增加一些额外的规定,比较就更加复杂了。
mysql5.1在字符集和校对规则的使用比其它大多数数据库管理系统超前许多,可以在任何级别进行使用和设置,为了有效地使用这些功能,你需要了解哪些字符集和 校对规则是可用的,怎样改变默认值,以及它们怎样影响字符操作符和字符串函数的行为。
校对规则一般有这些特征:
两个不同的字符集不能有相同的校对规则。
每个字符集有一个默认校对规则。例如,utf8默认校对规则是utf8_general_ci。
存在校对规则命名约定:它们以其相关的字符集名开始,通常包括一个语言名,并且以_ci(大小写不敏感)、_cs(大小写敏感)或_bin(二元)结束
确定默认字符集和校对
字符集和校对规则有4个级别的默认设置:服务器级、数据库级、表级和连接级。
数据库字符集和校对
每一个数据库有一个数据库字符集和一个数据库校对规则,它不能够为空。CREATE DATABASE和ALTER DATABASE语句有一个可选的子句来指定数据库字符集和校对规则:
例如:
CREATE DATABASE db_name DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
MySQL这样选择数据库字符集和数据库校对规则:
· 如果指定了CHARACTER SET X和COLLATE Y,那么采用字符集X和校对规则Y。
· 如果指定了CHARACTER SET X而没有指定COLLATE Y,那么采用CHARACTER SET X和CHARACTER SET X的默认校对规则。
· 否则,采用服务器字符集和服务器校对规则。
在SQL语句中使用COLLATE
•使用COLLATE子句,能够为一个比较覆盖任何默认校对规则。COLLATE可以用于多种SQL语句中。
使用WHERE:
select * from pro_product where product_code='ABcdefg' collate utf8_general_ci
Unicode与UTF8
Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储.Unicode码可以采用UCS-2格式直接存储.mysql支持ucs2字符集。
UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。
UTF8字符集(转换Unicode表示)是存储Unicode数据的一种可选方法。它根据 RFC 3629执行。UTF8字符集的思想是不同Unicode字符采用变长字节序列编码:
· 基本拉丁字母、数字和标点符号使用一个字节。
· 大多数的欧洲和中东手写字母适合两个字节序列:扩展的拉丁字母(包括发音符号、长音符号、重音符号、低音符号和其它音符)、西里尔字母、希腊语、亚美尼亚语、希伯来语、阿拉伯语、叙利亚语和其它语言。
· 韩语、中文和日本象形文字使用三个字节序列。