Monday 14 March 2016

MySQL 中文乱码解决方案

修改my.ini,如果此文件不存在,就在MySQL安装目录下(e.g. D:\mysql-5.1.34-win32)建立此文件

[mysql] 
default-character-set=gbk
[mysqld] 
default-character-set=gbk

稍微解释一下,[mysql] default-character-set=gbk就是告诉MySQL,现在客户端传过来的SQL包含有中文字符。
而[mysqld] default-character-set=gbk就是把MySQL的数据库改为中文编码。
用以下命令可以清晰地看到效果:
mysql> show variables like 'char%';
+--------------------------+---------------------------------------+
| Variable_name                 | Value                                 |
+--------------------------+---------------------------------------+
| character_set_client         | gbk                                   |
| character_set_connection | gbk                                   |
| character_set_database   | gbk                                   |
| character_set_filesystem  | binary                                |
| character_set_results       | gbk                                   |
| character_set_server       | gbk                                   |
| character_set_system      | utf8                                  |
| character_sets_dir           | D:\mysql-5.1.34-win32\share\charsets\ |
+--------------------------+---------------------------------------+

重启MySQL服务器后,以后建立的数据库和表都可以接受中文。

值得一提的是,在修改my.ini之前建立的数据库和表还是不能接受中文。需要找到数据库的dt.opt文件,比方以前建立过
create database mydb;

那么在D:\mysql-5.1.34-win32\data\mydb下,修改dt.opt

default-character-set=gbk
default-collation=gbk_chinese_ci

再重启服务器就可以了。

关于表的话,当然也可以用Alter命令修改,但更简单的方法就是drop再create一次就完了。

如果用Hibernate连接,只要简单地作如下配置

<property name="connection.url">jdbc:mysql://localhost:3361/mydb</property>

并不需要加上?useUnicode=true&amp;characterEncoding=GBK

JDK6和JBoss 5.0.0.GA的不兼容问题

  今天研究EJB3的web service过程中,出现一些问题,解决后觉得挺有心得,所以记录下来,已供将来参考。

环境:
  JDK6, JBoss 5.0.0.GA,Eclipse Helios。JBoss整合在Eclipse中。

问题:
  客户端访问部署在JBoss中的web service时,出现以下异常
java.lang.UnsupportedOperationException: setProperty must be overridden by all subclasses of SOAPMessage
 at javax.xml.soap.SOAPMessage.setProperty(SOAPMessage.java:445)
......

分析:
  JDK6中提供了web service相关的jar包,但和JBoss并不兼容。从这个例子中来看,就是JDK提供了一个SOAPMessage的类,同时JBoss也提供了同名的类(显然,内容是不一样的)。JBoss本意是要加载自己的类,但JVM classloading的顺序就是先加载JDK自己的核心类,再加载server的类。没办法,就这样被JDK的类捷足先登了。所以解决思路就2个,一个就是去除JDK6的SOAPMessage的类,如果只剩下一个类,那JVM也无从选择了。另一个思路就是设法使JBoss的SOAPMessage的类加载在先。

解决方案1:
  为了去除JDK6的SOAPMessage的类,不可能说去把这个jar包删掉,可行的方法就是放弃JDK6,而使用JDK5,JDK5中是没有这个类的。但这样我们就无法使用JDK6中的新功能了,以这样的代价去解决这个问题并不能令人满意。

解决方案2:
  在JBoss的路径中,找出包含SOAPMessage的jar包——jbossws-native-saaj.jar,放入<JAVA_HOME>\jre\lib\endorsed目录中。(如没有这个目录,则自己建立)

  为什么要放在endorsed目录下呢?原来放在这个目录下的class是优先于JDK核心类先被加载的。举例来说,大家都知道String类是final,所以无法继承。但你如果就是铁了心了要改写这个String类,也是有办法的,就是把这个新写的类打包成jar文件后放入endorsed目录下,这样JVM就会优先加载你这个String类了。

  所以这样一来,JBoss的SOAPMessage类就先被加载,这样就解决了问题。

  但这种解决方案也是有问题的,人家JDK6开发出SOAPMessage这个包终归是有用意的,它或许跟JBoss不兼容,但可能就跟Glassfish兼容的很好,如果以后要在这个机器上跑2个服务器,该怎么办呢?

  以我的知识所及,本来是想不出第三种,也就是最好的解决方案。但我在论坛中,看到有些人在同样的环境下运行的很好,完全没有发生错误。这使我很疑惑,究竟我跟他们之间有什么区别呢?

  抱着试试看的态度,我将JBoss的启动改为Commond Line方式启动,也即是双击bin目录下的run.bat。然后调用web service客户端,居然毫无问题。经过反复试验后,证明JBoss在Eclipse中运行就会出错,而在Commond Line下启动就没问题。这不得不使我去探索这两种启动方法到底有什么区别,也终于使我研究出了——

解决方案3:
  在Eclipse中,修改JBoss启动的VM Arguments,默认的是-Dprogram.name=run.bat -server -Xms128m -Xmx512m -XX:MaxPermSize=256m,在下面再加一句话

  -Djava.endorsed.dirs="D:\jboss-5.0.0.GA\lib\endorsed" (假设JBOSS_HOME=D:\jboss-5.0.0.GA)

  这句话的意思就是告诉JVM,这次启动,你要把D:\jboss-5.0.0.GA\lib\endorsed当作你的endorsed目录来启动。在这里你完全可以猜出D:\jboss-5.0.0.GA\lib\endorsed目录下一定有jbossws-native-saaj.jar。

  这么做的好处就是让这个配置只应用于JBoss的启动上,甚至说是只限于这个JBoss Server的instance。我完全可以再建立一个JBoss server,不加上那个参数,那么新的JBoss server还是只会以默认的方式启动。

  说实话,为了找出两种JBoss启动的不同,费了我可大的劲了。最后我是把run.bat中的@echo off去掉,让它把执行的话一句一句打印出来,最后才找到了这句参数。而一旦找到了这句话,一瞬间我就豁然开朗了。

总结:
  通过这次问题处理,一是巩固了对endorsed目录的作用的理解(原先只是模模糊糊大概知道那么回事),二是知道了-Djava.endorsed.dirs=...的用法,三是对类加载的顺序有了进一步的了解。

Union order by

select .... union select ... order by后面可以跟什么

只可以跟两样东西

1. 数字N,1<=N<=列数
2. union左边的select clause里的字段,如果有别名,必须用别名,不可以再用原来的字段名。不可以用字符串。

一个例子说明第二点

select employee_id id, first_name, 'c', 'c' ca from employees
union
select employee_id, first_name f_name, 'c', 'c' from employees
order by ?

order by 3 可以
order by employee_id 不可以,因为这个字段有了别名,本来的字段名就不能用了
order by id 可以
order by first_name 可以
order by f_name 不可以,union右边select clause的字段根本不用看
order by 'c' 不可以,因为是字符串
order by ca 可以,因为是别名,不是字符串了
order by lower(first_name) 不可以,表达式一律不允许

Modify constraint

SQL expert (1z0-047)的题库里有这样一道题,我觉得挺有意思的。

The ORDERS table contains data and all orders have been assigned a customer ID. Which statement would add a NOT NULL constraint to the existing CUSTOMER_ID column?

A. ALTER TABLE orders ADD CONSTRAINT orders_cust_id_nn NOT NULL (customer_id);
B. ALTER TABLE orders MODIFY customer_id CONSTRAINT orders_cust_id_nn NOT NULL;
C. ALTER TABLE orders MODIFY CONSTRAINT orders_cust_id_nn NOT NULL (customer_id);
D. ALTER TABLE orders ADD customer_id NUMBER(6)CONSTRAINT orders_cust_id_nn NOT NULL;

粗一看觉得答案是A。D肯定是错的,因为customer_id这个字段已经存在了。觉得BC错是因为我压根就没见过MODIFY CONSTRAINT这种用法。不是只有drop和add constraint吗?

答案却是B。

这是套用了ALTER TABLE table MODIFY column CONSTRAINT constraint inline_constraint的用法。

https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_3001.htm#i2103924

A为什么错了?因为ADD CONSTRAINT的用法是ALTER TABLE table ADD CONSTRAINT constraint out_of_line_constraint。

inline_constraint和out_of_line_constraint有什么区别?

http://docs.oracle.com/cd/E11882_01/server.112/e41084/clauses002.htm#SQLRF52180

主要区别就在于out_of_line_constraint不支持NULL/NOT NULL。其他的什么PRIMARY KEY, UNIQUE, CHECK, FOREIGN KEY都支持,当然格式有点不一样。

关于C,其实MODIFY CONSTRAINT是有的,用法是ALTER TABLE table MODIFY CONSTRAINT constraint_state。什么是constraint_state?

就是INITIALLY IMMEDIATE/DEFERRED, ENABLE/DISABLE, VALIDATE/NOVALIDATE这些东西,所以这个用法套不上的。

Key preserved table

What does mean by key preserved table?

According to its definition: A table is key-preserved if every key of the table can also be a key of the result of the join. So, a key-preserved table has its keys preserved through a join.

Let's illustrate this by an example.
 
create table a (a_id number primary key);
create table b (b_id number primary key, a_id number,
  foreign key (a_id) REFERENCES a(a_id) on delete cascade);

create or replace view c as (
  select a.a_id, b.b_id from a,b where a.a_id = b.a_id
)

insert into a values (1);
insert into b values (2,1);
insert into b values (3,1);

select * from c;

The result is
 
A_ID B_ID
---------
1    2
1    3

Clearly A's primary key A_ID cannot be used as a primary key in the view, so table A is not a key preserved table. On the other hand, table B's primary key B_ID can be used as a primary key in the view, so table B is a key preserved table for this view C.

So what happens when you
 
delete from c;

is all the rows in table B are deleted.

Rules for updating a join view

http://docs.oracle.com/cd/E11882_01/server.112/e25494/views.htm#ADMIN11782