开发网站使用MySQL的GPL协议问题

今天有花了很长时间看GPL协议的问题,终于有眉目了。我关心的不是分发或者卖我的软件该怎么绕开GPL协议,只是想知道我要开发一个网站,数据库用到了GPL的MySQL,那我也要遵守GPL协议,但是我该不该公布我的源代码?该不该开放整个网站的源代码?

网上的讨论很激烈,但是能解决问题的很少,很多是集中在我想用人家GPL的源代码在自己的程序里,或者用GPL的library,等等,其实,要想真的搞懂GPL,最好是乖乖地去看GPL的官方网站,这是我的最终感受。

http://www.gnu.org/licenses/gpl.html

这里有两个误区:

1. GPL与免费

很多人在网上搜索时包括我在内都在用类似的关键词查找“xxx GPL 免费” “XXX GPL free license”。其实GPL强调的是权利,具有GPL授权的软件的权利,“你可以自由使用;你可以获得源代码;你可以修改;你需要公布自己的源代码(在某种条件下)…” 听起来都很美,但是,它没有提到钱的问题,实际上它只关心你的权利和义务(right, not price),才不管你收不收费呢。假如你遵守GPL并且发布软件及源码,你硬要收费,那也行。只要有人肯付钱就行。所以很多GPL软件收费最多的其实是服务,而不是GPL软件本身。

2. 遵守GPL,就要开源 (至少是我的误区)

这里最最最关键的一点就是你有没有分发(distribute),传播(propagate),发布(convey)你的软件?如果没有,就不需要开源。有,就要开源。以我的例子:

我为公司开发网站用到GPL的MySQL,要开源我的网站系统吗?不用。因为我没有分发。作为GPL软件的使用者,我有权利运行使用它,覆盖它(cover),修改它,只要我不传播出去。

以下是我在官方网站上找到的证明:

引用
http://www.gnu.org/licenses/gpl-faq.html

A company is running a modified version of a GPL’ed program on a web site. Does the GPL say they must release their modified sources 

The GPL permits anyone to make a modified version and use it without ever distributing it to others. What this company is doing is a special case of that. Therefore, the company does not have to release the modified sources.

It is essential for people to have the freedom to make modifications and use them privately, without ever publishing those modifications. However, putting the program on a server machine for the public to talk to is hardly “private” use, so it would be legitimate to require release of the source code in that special case. Developers who wish to address this might want to use the GNU Affero GPL for programs designed for network server use.

Is making and using multiple copies within one organization or company “distribution” 

No, in that case the organization is just making the copies for itself. As a consequence, a company or other organization can develop a modified version and install that version through its own facilities, without giving the staff permission to release that modified version to outsiders.

However, when the organization transfers copies to other organizations or individuals,  that is distribution. In particular, providing copies to contractors for use off-site is distribution.

If I only make copies of a GPL-covered program and run them, without distributing or conveying them to others, what does the license require of me 

Nothing. The GPL does not place any conditions on this activity.

MySQL分表优化试验PROCEDURE

MySQL分表优化之试验PROCEDURE

  DELIMITER $$

  DROP PROCEDURE `t_girl`.`sp_split_table`$$

  CREATE PROCEDURE `t_girl`.`sp_split_table`()

  BEGIN

  declare done int default 0;

  declare v_user_name varchar(20) default ”;

  declare v_table_name varchar(64) default ”;

  – Get all users’ name.

  declare cur1 cursor for select user_name from t_group group by user_name;

  – Deal with error or warnings.

  declare continue handler for 1329 set done = 1;

  – Open cursor.

  open cur1;

  while done <> 1

  do

  fetch cur1 into v_user_name;

  if not done then

  – Get table name.

  set v_table_name = concat(‘t_group_’,v_user_name);

  – Create new extra table.

  set @stmt = concat(‘create table ‘,v_table_name,’ like t_group’);

  prepare s1 from @stmt;

  execute s1;

  drop prepare s1;

  – Load data into it.

  set @stmt = concat(‘insert into ‘,v_table_name,’ select * from t_group where user_name = ”’,v_user_name,””);

  prepare s1 from @stmt;

  execute s1;

  drop prepare s1;

  end if;

  end while;

  – Close cursor.

  close cur1;

  – Free variable from memory.

  set @stmt = NULL;

  END$$

  DELIMITER ;

本文来自学习网原地址文:http://www.zznyy.com/jisuanji/shujuku/2010-05-11/1867.html

MySQLProxy-官方的MySQL连接池和代理工具

MySQL Proxy 可以理解为类似SQL Relay的连接池工具,不过它要更强大一点,看看官方描述的特性:

* load balancing
* failover
* query analysis
* query filtering and modification
* … and many more

它包括了查询分析(query analysis & query filtering),并可以根据分析结果,决定转发方向. 完成了一主多从,或一主(一备主)多从中,写和读操作的完美区分.为replication提供了更多的应用空间,同时还有负载均衡,失败转移等等高级功能,套用一句俗话:为我们的MySQL保驾护航。

目前MySQL Proxy的最新版本是0.5.1,不算很稳定吧,尝试性的使用应该是没有太多问题的,不过使用也稍微比较麻烦,我还没有正式测试。

附上相关链接

官方网站:http://forge.mysql.com/wiki/MySQL_Proxy
下载地址:http://dev.mysql.com/downloads/mysql-proxy/0.5.html
官方文档:http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy.html
开发博客:http://jan.kneschke.de/
入门教程:http://www.oreillynet.com/pub/a/databases/2007/07/12/getting-started-with-mysql-proxy.html

mysql命令不常用的参数

mysql -e   这个参数是告诉mysql 我只要执行”-e” 后面的某个命令,而不是要通过mysql连接到mysql server上面,此参数在写一些基本的mysql检查和监控的脚本中非常有用

mysql -H,–htlm   这个参数 select出来的结果都会按照Html格式输出,在某些场后下,比如希望用Html格式导出报表文件时

mysql -X,–xml    这个参数 select出来的结果都会按照Xml格式输出,在某些场后下,比如希望用Xml格式导出报表文件时

mysql –prompt 这个参数对于维护人员很重要,主要功能是定制自己的mysql提示符显示内容,默认的mysql的提示符是>   如果我们使用mysql时,自定义提示符,如 mysql –prompt “\\u@\\h:\\d \\r:\\m:\\s>”   它的显示效果就是这样:root@localhost:db2 10:53:25> 是不是很方面   能马上知道现在用的是那个数据库!

mysql –tee 这个参数对于运维人员非常有用的参数,用来告诉Mysql将所有输入和输出内容都记录到文件里,当做有些较大维护变更的时候,为了方便查找,最好是将这个操作过程所有输入和输出都记录下来 例如:mysql –tee=/root/mysql.txt

————————————-

-D 指定 数据库名称

-P 指定 端口号

-p 指定 密码

jforum数据库字典

数据字典(非官方版) For Jforum 2.1.8

author:邓华锋

date: 2010-10-3

Email:denghuafeng@live.cn

Company: YueGou

Copyright: Copyright (c) 2010

jforum_users会员表

表说明:记录会员信息。

字段 类型 Null 默认 注释

user_id int(11) 否 主键,会员编号,自增

user_active tinyint(1) 是 0 是否启用此账号

username varchar(50) 否 “” 唯一,会员用户名

user_password varchar(32) 否 “” 会员密码

user_session_time bigint(20) 是 0 时间格式

user_session_page int(11) 否 0 每页显示主题数

user_lastvisit datetime 是 最后访问时间

user_regdate datetime 是 注册时间

user_level tinyint(4) 是 用户发帖等级

user_posts int(11) 否 0 发帖数

user_timezone varchar(5) 否 “” 时差设定

user_style tinyint(4) 是 界面风格

user_lang varchar(255) 否 “” 语言选择

user_dateformat varchar(20) 否 %d/%M/%Y %H:%i 日期格式

user_new_privmsg int(11) 否 0 最新短信息

user_unread_privmsg int(11) 否 0 未读短信息

user_last_privmsg datetime 是 最后发送短信息时间

user_emailtime datetime 是 发送Email时间

user_viewemail tinyint(1) 是 0 是否显示电子邮箱(0否,1是)

user_attachsig tinyint(1) 是 1 是否在文章内附加个性签名(0否,1是)

user_allowhtml tinyint(1) 是 0 是否使用 HTML 语法(0否,1是)

user_allowbbcode tinyint(1) 是 1 是否使用 BBCode 代码(0否,1是)

user_allowsmilies tinyint(1) 是 1 是否使用表情符号(0否,1是)

user_allowavatar tinyint(1) 是 1 是否封锁(0是,1否,)

user_allow_pm tinyint(1) 是 1 是否允许发短信息(0否,1是)

user_allow_viewonline tinyint(1) 是 1 是否允许显示上线(0否,1是)

user_notify tinyint(1) 是 1 是否设置回复通知(0否,1是)

user_notify_always tinyint(1) 是 0 是否发送所有新文章的提示邮件(0否,1是)

user_notify_text tinyint(1) 是 0 是否在提示邮件中包含文章内容(0否,1是)

user_notify_pm tinyint(1) 是 1 当有新的短信时是否以电子邮件通知(0否,1是)

user_popup_pm tinyint(1) 是 1 是否提示有新短消息(0否,1是)

rank_id int(11) 是 0 排行榜序号

user_avatar varchar(100) 是 头像文件名

user_avatar_type tinyint(4) 否 0 头像类型

user_email varchar(255) 否 “” 电子邮箱

user_icq varchar(15) 是 icq号码

user_website varchar(255) 是 个人网站

user_from varchar(100) 是 来自

user_sig text 是 个性签名

user_sig_bbcode_uid varchar(10) 是 bbcode个性签名

user_aim varchar(255) 是 AIM美国在线即时通讯软件

user_yim varchar(255) 是 Yahoo!即时通

user_msnm varchar(255) 是 MSN

user_occ varchar(100) 是 OCC

user_interests varchar(255) 是 兴趣

user_biography text 是 自我介绍

user_actkey varchar(32) 是 访问密钥

gender char(1) 是 性别(0=保密 1=男 2=女)

themes_id int(11) 是 个人空间主题ID

deleted tinyint(1) 是 此用户是否已经删除

user_viewonline tinyint(1) 是 1 是否显示上线状态(0否,1是)

security_hash varchar(32) 是 用户安全提问

user_karma double 是 积分

user_authhash varchar(32) 是 用户安全问题答案

jforum_groups会员组表

表说明:记录用户组信息。

字段 类型 Null 默认 注释

group_id int(11) 否 主键,会员组编号,自增

group_name varchar(40) 否 “” 会员组名称

group_description varchar(255) 否 会员组描述

parent_id int(11) 否 0 所在会员组group_id

jforum_user_groups 会员与会员组关联表

表说明:设置会员所在会员组。

字段 类型 Null 默认 注释

group_id int(11) 否 关联主键,会员组的group_id

user_id int(11) 否 关联主键,会员的user_id

jforum_roles 会员组权限表

表说明:记录会员组所具有的权限。

字段 类型 Null 默认 注释

role_id int(11) 否 主键,权限编号,自增

group_id int(11) 否 关联主键,会员组的group_id

name varchar(255) 否 权限名称

jforum_categories版面分类表

表说明:记录用户组信息。

字段 类型 Null 默认 注释

categories_id int(11) 否 主键,版面分类编号,自增

title varchar(100) 否 “” 版面分类名称

display_order varchar(11) 否 0 排序序号

moderated tinyint(1) 是 0 是否审核此版面分类(0否,1是)

jforum_forums版面表

表说明:记录版面信息。

字段 类型 Null 默认 注释

forum_id int(11) 否 主键,版面编号,自增

categories_id int(11) 否 1 版面分类ID

forum_name varchar(150) 否 “” 版面名称

forum_desc varchar(255) 是 版面描述

forum_order int(11) 是 1 版面排列序号

forum_topics int(11) 否 0 主题数

forum_last_post_id int(11) 否 0 最后回帖ID

moderated tinyint(1) 是 0 是否审核此版面(0否,1是)

jforum_role_values 版面权限表

表说明:设置版面权限信息。

字段 类型 Null 默认 注释

role_id int(11) 否 关联主键,会员组权限表role_id

role_value varchar(255) 是 关联版面forum_id

jforum_forums_watch订阅版面表

表说明:记录会员订阅的版面,注:在mysql_db_struct.sql文件中创建此表的sql语句中少了“is_read INT DEFAULT 1”,从而此表导致少了“is_read”列。

字段 类型 Null 默认 注释

forum_id int(11) 否 关联主键,版面forum_id

user_id int(11) 否 关联主键,订阅者,索引,会员user_id

is_read tinyint(1) 是 1 是否已读(0否,1是)

jforum_posts帖子表

表说明:记录帖子信息。

字段 类型 Null 默认 注释

post_id int(11) 否 主键,帖子编号,自增

topic_id int(11) 否 0 所属主题topic_id

forum_id int(11) 否 0 所在版块ID

user_id int(11) 否 0 索引,主题作者user_id

post_time datetime 是 发表时间

poster_ip varchar(15) 是 发表者IP

enable_bbcode tinyint(1) 否 1 是否使用BBCode 代码功能(0否,1是)

enable_html tinyint(1) 否 1 是否使用HTML 功能(0否,1是)

enable_smilies tinyint(1) 否 1 是否使用表情符号功能(0否,1是)

enable_sig tinyint(1) 否 1 是否附加个性签名(0否,1是)

post_edit_time datetime 是 编辑时间

post_edit_count int(11) 否 0 编辑次数

status tinyint(1) 是 1 状态

attach tinyint(1) 是 0 是否具有上传附件功能(0否,1是)

need_moderate tinyint(1) 是 0 是否当有人回复文章时通知我(0否,1是)

jforum_posts_text帖子内容表

表说明:记录帖子的内容。

字段 类型 Null 默认 注释

post_id int(11) 否 0 主键,关联为帖子的post_id

post_text text 是 帖子内容

post_subject varchar(100) 是 帖子主题

更多表的信息,请下载后查看!~

注:如需转载,请注明出处,以上有什么地方不对,欢迎交流解答!Email:denghuafeng@live.cn

浅谈unique列上插入重复值的MySQL解决方案

本文的unique列上插入重复值解决方案,主要基于MySQL平台。通过这些,可以做到一些新的功能和应用。希望本文能对大家有所帮助。

当unique列在一个UNIQUE键上插入包含重复值的记录时,我们可以控制MySQL如何处理这种情况:使用IGNORE关键字或者ON DUPLICATE KEY UPDATE子句跳过INSERT、中断操作或者更新旧记录为新值。

  1. mysql> create table menus(id tinyint(4) not null auto_increment,  
  2.    -> label varchar(10) null,url varchar(20) null,unique key(id));  
  3. Query OK, 0 rows affected (0.13 sec)  
  4. mysql> insert into menus(label,url) values('Home','home.html');  
  5. Query OK, 1 row affected (0.06 sec)  
  6. mysql> insert into menus(label,url) values('About us','aboutus.html');  
  7. Query OK, 1 row affected (0.05 sec)  
  8. mysql> insert into menus(label,url) values('Services','services.html');  
  9. Query OK, 1 row affected (0.05 sec)  
  10. mysql> insert into menus(label,url) values('Feedback','feedback.html');  
  11. Query OK, 1 row affected (0.05 sec) 
  1. mysql> select * from menus;  
  2. +----+----------+---------------+  
  3. | id | label   | url          |  
  4. +----+----------+---------------+  
  5. | 1 | Home    | home.html    |  
  6. | 2 | About us | aboutus.html |  
  7. | 3 | Services | services.html |  
  8. | 4 | Feedback | feedback.html |  
  9. +----+----------+---------------+  
  10. rows in set (0.00 sec) 

如果现在在unique列插入一条违背唯一约束的记录,MySQL会中断操作,提示出错:

  1. mysql> insert into menus(id,label,url) values(4,'Contact us','contactus.html');  
  2. ERROR 1062 (23000): Duplicate entry '4' for key 'id' 

在前面的INSERT语句添加IGNORE关键字时,如果认为语句违背了唯一约束,MySQL甚至不会尝试去执行这条语句,因此,下面的语句不会返回错误:

  1. mysql> insert ignore into menus(id,label,url) values(4,'Contact us','contactus.html');  
  2. Query OK, 0 rows affected (0.00 sec)  
  3. mysql> select * from menus;  
  4. +----+----------+---------------+  
  5. | id | label   | url          |  
  6. +----+----------+---------------+  
  7. | 1 | Home    | home.html    |  
  8. | 2 | About us | aboutus.html |  
  9. | 3 | Services | services.html |  
  10. | 4 | Feedback | feedback.html |  
  11. +----+----------+---------------+  
  12. rows in set (0.00 sec) 

当有很多的INSERT语句需要被顺序地执行时,IGNORE关键字就使操作变得很方便。使用它可以保证不管哪一个INSERT包含了重复的键值,MySQL都回跳过它(而不是放弃全部操作)。

在这种情况下,我们还可以通过添加MySQL4.1新增加的ON DUPLICATE KEY UPDATE子句,使MySQL自动把INSERT操作转换为UPDATE操作。这个子句必须具有需要更新的字段列表,这个列表和UPDATE语句使用的列表相同。

  1. mysql> insert into menus(id,label,url) values(4,'Contact us','contactus.html')  
  2.    -> on duplicate key update label='Contact us',url='contactus.html';  
  3. Query OK, 2 rows affected (0.05 sec) 

在这种情况下,如果MySQL发现表已经包含具有相同唯一键的记录,它会自动更新旧的记录为ON DUPLICATE KEY UPDATE从句中指定的新值:

  1. mysql> select * from menus;  
  2. +----+------------+----------------+  
  3. | id | label     | url           |  
  4. +----+------------+----------------+  
  5. | 1 | Home      | home.html     |  
  6. | 2 | About us  | aboutus.html  |  
  7. | 3 | Services  | services.html |  
  8. | 4 | Contact us | contactus.html |  
  9. +----+------------+----------------+  
  10. rows in set (0.01 sec) 

JAVA综合面试题:页面的抓取、解析、保存数据库和生成HTML的页面展示

写一个jsp页面,访问时显示从下面的页面提取出的销售商详细信息:价格、运费、经销
商基本信息等,并写到一个数据库表里。
http://www.amazon.com/gp/offer-listing/B0012J52OC/

数据抓取的问题,涉及到
1 用URLConnection 读取页面信息,用httpclient也行
2 用Pattern 解析页面并拿到你要的信息
3 显示数据
4 存入数据库

这个是一个综合的考试,涉及的知识面比较广。

1 我这里只给出关键的部分,使用java程序实现,而不是JSP的代码。移植工作请自行完成。
2 我使用自己的数据库连接,请替换为应用服务器提供的数据源为好
3 代码分三部分,数据库结构,POJO类和应用程序

一、数据库结构 AmazonGoods.sql 使用的是MySQL的数据库

  1. — —————————-   
  2. — Table structure for amazongoods   
  3. — —————————-   
  4. CREATE TABLE `amazongoods` (   
  5.   `id` int(11) NOT NULL AUTO_INCREMENT,   
  6.   `price` decimal(10,0) NOT NULL,   
  7.   `shipping` decimal(10,0) NOT NULL,   
  8.   `Seller` text NOT NULL,   
  9.   PRIMARY KEY (`id`)   
  10. ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;  
-- ----------------------------
-- Table structure for amazongoods
-- ----------------------------
CREATE TABLE `amazongoods` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `price` decimal(10,0) NOT NULL,
  `shipping` decimal(10,0) NOT NULL,
  `Seller` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

二、POJO类 AmazonGoods.java

  1. package com.laozizhu.test.amazon;   
  2.   
  3. import java.math.BigDecimal;   
  4.   
  5. /**  
  6.  * 某一行的商品数据  
  7.  *   
  8.  * @author 老紫竹的家(laozizhu.com)  
  9.  *   
  10.  */  
  11. class AmazonGoods {   
  12.   public long getId() {   
  13.     return id;   
  14.   }   
  15.   
  16.   public void setId(long id) {   
  17.     this.id = id;   
  18.   }   
  19.   
  20.   public BigDecimal getPrice() {   
  21.     return price;   
  22.   }   
  23.   
  24.   public void setPrice(BigDecimal price) {   
  25.     this.price = price;   
  26.   }   
  27.   
  28.   public BigDecimal getShipping() {   
  29.     return shipping;   
  30.   }   
  31.   
  32.   public void setShipping(BigDecimal shipping) {   
  33.     this.shipping = shipping;   
  34.   }   
  35.   
  36.   public String getSeller() {   
  37.     return seller;   
  38.   }   
  39.   
  40.   public void setSeller(String seller) {   
  41.     this.seller = seller;   
  42.   }   
  43.   
  44.   // 序列号,主键   
  45.   private long id;   
  46.   // 价格   
  47.   private BigDecimal price;   
  48.   // 运费   
  49.   private BigDecimal shipping;   
  50.   // 商家信息   
  51.   private String seller;   
  52. }  
package com.laozizhu.test.amazon;

import java.math.BigDecimal;

/**
 * 某一行的商品数据
 * 
 * @author 老紫竹的家(laozizhu.com)
 * 
 */
class AmazonGoods {
  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public BigDecimal getPrice() {
    return price;
  }

  public void setPrice(BigDecimal price) {
    this.price = price;
  }

  public BigDecimal getShipping() {
    return shipping;
  }

  public void setShipping(BigDecimal shipping) {
    this.shipping = shipping;
  }

  public String getSeller() {
    return seller;
  }

  public void setSeller(String seller) {
    this.seller = seller;
  }

  // 序列号,主键
  private long id;
  // 价格
  private BigDecimal price;
  // 运费
  private BigDecimal shipping;
  // 商家信息
  private String seller;
}

三、应用类

  1. package com.laozizhu.test.amazon;   
  2.   
  3. import java.math.BigDecimal;   
  4. import java.sql.Connection;   
  5. import java.sql.DriverManager;   
  6. import java.sql.PreparedStatement;   
  7. import java.util.ArrayList;   
  8. import java.util.List;   
  9. import java.util.Properties;   
  10. import java.util.regex.Matcher;   
  11. import java.util.regex.Pattern;   
  12.   
  13. import com.laozizhu.tools.PageService;   
  14.   
  15. public class AmazonFetch {   
  16.   
  17.   /**  
  18.    * @param args  
  19.    */  
  20.   public static void main(String[] args) {   
  21.     // 我这里需要设置代理,如果你能直接访问互联网,则无需这段代码了   
  22.     initProxy();   
  23.   
  24.     // 读取页面数据   
  25.     String str = PageService.getPage(“http://www.amazon.com/gp/offer-listing/B0012J52OC/”“ISO-8859-1”);   
  26.     // 解析页面,拿到商品信息   
  27.     List<AmazonGoods> list = parse(str);   
  28.     // 生成HTML表格   
  29.     buildTable(list);   
  30.     // 存入数据库   
  31.     saveToMySQL(list);   
  32.   }   
  33.   
  34.   /**  
  35.    * 简单的代理服务器,无需密码认证  
  36.    */  
  37.   private static void initProxy() {   
  38.     Properties prop = System.getProperties();   
  39.     // prop.put(“proxySet”, “true”);   
  40.     // 设置http访问要使用的代理服务器的地址   
  41.     prop.setProperty(“http.proxyHost”“10.60.8.20”);   
  42.     // 设置http访问要使用的代理服务器的端口   
  43.     prop.setProperty(“http.proxyPort”“8080”);   
  44.   }   
  45.   
  46.   // 注意,美元符号要转义   
  47.   // 因为报价都包含小数点,所以用数字+小数点+2位小数即可   
  48.   // 商家信息包含了对应的标签   
  49.   static Pattern pPrice = Pattern.compile(   
  50.       “<span class=\”price\”>\\$([\\d]+\\.[\\d]{2})</span>.* (<ul class=\”sellerInformation\”>.+ </ul>)”, Pattern.DOTALL);   
  51.   // 运费   
  52.   // <span class=”price_shipping”>+ $6.04</span>   
  53.   static Pattern pShipping = Pattern   
  54.       .compile(“<span class=\”price_shipping\”>\\+ \\$([\\d]+\\.[\\d]{2})</span>”, Pattern.DOTALL);   
  55.   
  56.   /**  
  57.    * 解析页面,获得商品列表  
  58.    *   
  59.    * @param page  
  60.    *          页面  
  61.    * @return 商品列表  
  62.    */  
  63.   private static List<AmazonGoods> parse(String page) {   
  64.     // 首先,把商品分成多个字符串片段   
  65.     // 分割符就是表格里的内容了。这个得查看HTML源代码才能找到合适的   
  66.     String[] strs = page.split(“<tbody class=\”result\”>”);   
  67.     // 构造结果   
  68.     // 默认长度为片段的长度,呵呵   
  69.     List<AmazonGoods> list = new ArrayList<AmazonGoods>(strs.length);   
  70.     AmazonGoods goods = null;   
  71.     // 循环解析每个商品片段   
  72.     for (String str : strs) {   
  73.       // 注意,不是每个商品都有运费,所以正则最好不要写一个   
  74.       // 当然,你愿意弄复杂了也行,我个人不推荐这么做   
  75.       Matcher m = pPrice.matcher(str);   
  76.       if (m.find()) {   
  77.         goods = new AmazonGoods();   
  78.         goods.setPrice(new BigDecimal(m.group(1)));   
  79.         // 这里面包含了HTML的信息,包括Javascript内容,不过比较难删除   
  80.         // 因为有些页面文字是用js显示的,还是保留的比较好   
  81.         goods.setSeller(m.group(2));   
  82.   
  83.         // 查找运费   
  84.         m = pShipping.matcher(str);   
  85.         if (m.find()) {   
  86.           goods.setShipping(new BigDecimal(m.group(1)));   
  87.         }   
  88.         // 将商品加入列表   
  89.         list.add(goods);   
  90.       } else {   
  91.         // 没有找到价格,则这部分不包含商品信息,无需继续   
  92.         continue;   
  93.       }   
  94.     }   
  95.     return list;   
  96.   }   
  97.   
  98.   private static String buildTable(List<AmazonGoods> list) {   
  99.     StringBuilder b = new StringBuilder(“<table>”);   
  100.     b.append(“<tr><th>价格</th><th>运费</th><th>商家信息</th></tr>”);   
  101.     for (AmazonGoods goods : list) {   
  102.       b.append(“<tr><th>” + goods.getPrice() + “</th><th>” + goods.getShipping() + “</th><th>” + goods.getSeller()   
  103.           + “</th></tr>”);   
  104.     }   
  105.     b.append(“</table>”);   
  106.     return b.toString();   
  107.   }   
  108.   
  109.   private static void saveToMySQL(List<AmazonGoods> list) {   
  110.     // 这里就用最原始的方法获得数据库连接了。   
  111.     // 数据库结构请参考AmazonGoods.sql   
  112.     // 使用test的数据库   
  113.     Connection con = null;   
  114.     PreparedStatement st = null;   
  115.     String url = “jdbc:mysql://localhost:3306/”;   
  116.     String db = “test”;   
  117.     String driver = “com.mysql.jdbc.Driver”;   
  118.     String user = “test”;   
  119.     String pass = “test”;   
  120.     BigDecimal ZERO = new BigDecimal(“0”);   
  121.     try {   
  122.       Class.forName(driver);   
  123.       con = DriverManager.getConnection(url + db, user, pass);   
  124.       st = con.prepareStatement(“insert into AmazonGoods (price,shipping,seller) values( , , )”);   
  125.       for (AmazonGoods goods : list) {   
  126.         st.setBigDecimal(1, goods.getPrice());   
  127.         st.setBigDecimal(2, goods.getShipping()==null ZERO:goods.getShipping());   
  128.         st.setString(3, goods.getSeller());   
  129.         if (st.executeUpdate() <= 0) {   
  130.           throw new Exception(“保存数据错误!”);   
  131.         }   
  132.         st.clearParameters();   
  133.       }   
  134.   
  135.     } catch (Exception ex) {   
  136.       ex.printStackTrace();   
  137.     } finally {   
  138.       if (st != null) {   
  139.         try {   
  140.           st.close();   
  141.         } catch (Exception ex) {   
  142.         }   
  143.       }   
  144.       if (con != null) {   
  145.         try {   
  146.           con.close();   
  147.         } catch (Exception ex) {   
  148.         }   
  149.       }   
  150.     }   
  151.   }   
  152. }  
package com.laozizhu.test.amazon;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.laozizhu.tools.PageService;

public class AmazonFetch {

  /**
   * @param args
   */
  public static void main(String[] args) {
    // 我这里需要设置代理,如果你能直接访问互联网,则无需这段代码了
    initProxy();

    // 读取页面数据
    String str = PageService.getPage("http://www.amazon.com/gp/offer-listing/B0012J52OC/", "ISO-8859-1");
    // 解析页面,拿到商品信息
    List<AmazonGoods> list = parse(str);
    // 生成HTML表格
    buildTable(list);
    // 存入数据库
    saveToMySQL(list);
  }

  /**
   * 简单的代理服务器,无需密码认证
   */
  private static void initProxy() {
    Properties prop = System.getProperties();
    // prop.put("proxySet", "true");
    // 设置http访问要使用的代理服务器的地址
    prop.setProperty("http.proxyHost", "10.60.8.20");
    // 设置http访问要使用的代理服务器的端口
    prop.setProperty("http.proxyPort", "8080");
  }

  // 注意,美元符号要转义
  // 因为报价都包含小数点,所以用数字+小数点+2位小数即可
  // 商家信息包含了对应的标签
  static Pattern pPrice = Pattern.compile(
      "<span class=\"price\">\\$([\\d]+\\.[\\d]{2})</span>.* (<ul class=\"sellerInformation\">.+ </ul>)", Pattern.DOTALL);
  // 运费
  // <span class="price_shipping">+ $6.04</span>
  static Pattern pShipping = Pattern
      .compile("<span class=\"price_shipping\">\\+ \\$([\\d]+\\.[\\d]{2})</span>", Pattern.DOTALL);

  /**
   * 解析页面,获得商品列表
   * 
   * @param page
   *          页面
   * @return 商品列表
   */
  private static List<AmazonGoods> parse(String page) {
    // 首先,把商品分成多个字符串片段
    // 分割符就是表格里的内容了。这个得查看HTML源代码才能找到合适的
    String[] strs = page.split("<tbody class=\"result\">");
    // 构造结果
    // 默认长度为片段的长度,呵呵
    List<AmazonGoods> list = new ArrayList<AmazonGoods>(strs.length);
    AmazonGoods goods = null;
    // 循环解析每个商品片段
    for (String str : strs) {
      // 注意,不是每个商品都有运费,所以正则最好不要写一个
      // 当然,你愿意弄复杂了也行,我个人不推荐这么做
      Matcher m = pPrice.matcher(str);
      if (m.find()) {
        goods = new AmazonGoods();
        goods.setPrice(new BigDecimal(m.group(1)));
        // 这里面包含了HTML的信息,包括Javascript内容,不过比较难删除
        // 因为有些页面文字是用js显示的,还是保留的比较好
        goods.setSeller(m.group(2));

        // 查找运费
        m = pShipping.matcher(str);
        if (m.find()) {
          goods.setShipping(new BigDecimal(m.group(1)));
        }
        // 将商品加入列表
        list.add(goods);
      } else {
        // 没有找到价格,则这部分不包含商品信息,无需继续
        continue;
      }
    }
    return list;
  }

  private static String buildTable(List<AmazonGoods> list) {
    StringBuilder b = new StringBuilder("<table>");
    b.append("<tr><th>价格</th><th>运费</th><th>商家信息</th></tr>");
    for (AmazonGoods goods : list) {
      b.append("<tr><th>" + goods.getPrice() + "</th><th>" + goods.getShipping() + "</th><th>" + goods.getSeller()
          + "</th></tr>");
    }
    b.append("</table>");
    return b.toString();
  }

  private static void saveToMySQL(List<AmazonGoods> list) {
    // 这里就用最原始的方法获得数据库连接了。
    // 数据库结构请参考AmazonGoods.sql
    // 使用test的数据库
    Connection con = null;
    PreparedStatement st = null;
    String url = "jdbc:mysql://localhost:3306/";
    String db = "test";
    String driver = "com.mysql.jdbc.Driver";
    String user = "test";
    String pass = "test";
    BigDecimal ZERO = new BigDecimal("0");
    try {
      Class.forName(driver);
      con = DriverManager.getConnection(url + db, user, pass);
      st = con.prepareStatement("insert into AmazonGoods (price,shipping,seller) values( , , )");
      for (AmazonGoods goods : list) {
        st.setBigDecimal(1, goods.getPrice());
        st.setBigDecimal(2, goods.getShipping()==null ZERO:goods.getShipping());
        st.setString(3, goods.getSeller());
        if (st.executeUpdate() <= 0) {
          throw new Exception("保存数据错误!");
        }
        st.clearParameters();
      }

    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
      if (st != null) {
        try {
          st.close();
        } catch (Exception ex) {
        }
      }
      if (con != null) {
        try {
          con.close();
        } catch (Exception ex) {
        }
      }
    }
  }
}

四、辅助类 PageService.java

  1. package com.laozizhu.tools;   
  2.   
  3. import java.io.BufferedReader;   
  4. import java.io.FileNotFoundException;   
  5. import java.io.InputStream;   
  6. import java.io.InputStreamReader;   
  7. import java.io.OutputStream;   
  8. import java.net.ConnectException;   
  9. import java.net.HttpURLConnection;   
  10. import java.net.URL;   
  11. import java.util.zip.GZIPInputStream;   
  12.   
  13. /**  
  14.  * 读取URL的文本工具  
  15.  *   
  16.  * @author 赵学庆 <A href=”www.java2000.net” target=_blank>www.java2000.net</A>  
  17.  */  
  18. public class PageService {   
  19.   private static final String BR = “\r\n”;   
  20.   
  21.   /**  
  22.    * 读取文本。默认使用UTF-8编码  
  23.    *   
  24.    * @param page  
  25.    *          页面的URL,比如 <A href=”http://www.java2000.net” target=_blank>http://www.java2000.net</A>  
  26.    * @return 读取到的文本字符串  
  27.    */  
  28.   public static String getPage(String page) {   
  29.     return getPage(page, “UTF-8”);   
  30.   }   
  31.   
  32.   /**  
  33.    * 读取文本  
  34.    *   
  35.    * @param page  
  36.    *          页面的URL,比如 <A href=”http://www.java2000.net” target=_blank>http://www.java2000.net</A>  
  37.    * @param charset  
  38.    *          页面的编码  
  39.    * @return 读取到的文本字符串  
  40.    */  
  41.   public static String getPage(String page, String charset) {   
  42.     String str = null;   
  43.     int count = 3;   
  44.     do {   
  45.       str = _getPage(page, charset);   
  46.       if (str == null || str.length() == 0) {   
  47.         try {   
  48.           Thread.sleep(1000);   
  49.         } catch (InterruptedException e) {   
  50.           e.printStackTrace();   
  51.         }   
  52.       }   
  53.     } while (str == null && count– > 0);   
  54.     return str;   
  55.   }   
  56.   
  57.   private static String _getPage(String page, String charset) {   
  58.     try {   
  59.       URL url = new URL(page);   
  60.       HttpURLConnection con = (HttpURLConnection) url.openConnection();   
  61.       // 增加了浏览器的类型,就用Firefox好了,也许   
  62.       con   
  63.           .setRequestProperty(   
  64.               “User-Agent”,   
  65.               “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727)”);   
  66.       int index = page.indexOf(“/”10);   
  67.       con.setRequestProperty(“Host”, index == –1   page.substring(7) : page   
  68.           .substring(7, index));   
  69.       InputStream is = con.getInputStream();   
  70.       if (con.getContentEncoding() != null  
  71.           && con.getContentEncoding().equalsIgnoreCase(“gzip”)) {   
  72.         is = new GZIPInputStream(con.getInputStream());   
  73.       }   
  74.       BufferedReader reader = new BufferedReader(new InputStreamReader(is,   
  75.           charset));   
  76.       StringBuilder b = new StringBuilder();   
  77.       String line;   
  78.       while ((line = reader.readLine()) != null) {   
  79.         b.append(line);   
  80.         b.append(BR);   
  81.       }   
  82.       reader.close();   
  83.       return b.toString();   
  84.     } catch (FileNotFoundException ex) {   
  85.       System.out.println(“NOT FOUND:” + page);   
  86.       return null;   
  87.     } catch (ConnectException ex) {   
  88.       System.out.println(“Timeout:” + page);   
  89.       return null;   
  90.     } catch (Exception ex) {   
  91.       ex.printStackTrace();   
  92.       return null;   
  93.     }   
  94.   }   
  95.   
  96.   public static String postPage(String page, String msg) throws Exception {   
  97.     URL url = new URL(page);   
  98.     HttpURLConnection con = (HttpURLConnection) url.openConnection();   
  99.     con.setDoOutput(true); // POST方式   
  100.     con   
  101.         .setRequestProperty(   
  102.             “User-Agent”,   
  103.             “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727)”);   
  104.     int index = page.indexOf(“/”10);   
  105.     con.setRequestProperty(“Host”, index == –1   page.substring(7) : page   
  106.         .substring(7, index));   
  107.     con.setRequestMethod(“POST”);   
  108.     con.addRequestProperty(“Content-Type”“application/x-www-form-urlencoded”);   
  109.     OutputStream os = con.getOutputStream(); // 输出流,写数据   
  110.     os.write(msg.getBytes(“UTF-8”));   
  111.     InputStream is = con.getInputStream();   
  112.     if (con.getContentEncoding() != null  
  113.         && con.getContentEncoding().equalsIgnoreCase(“gzip”)) {   
  114.       is = new GZIPInputStream(con.getInputStream());   
  115.     }   
  116.     BufferedReader reader = new BufferedReader(new InputStreamReader(is,   
  117.         “UTF-8”)); // 读取结果   
  118.     StringBuilder b = new StringBuilder();   
  119.     String line;   
  120.     while ((line = reader.readLine()) != null) {   
  121.       b.append(line);   
  122.       b.append(BR);   
  123.     }   
  124.     os.close();   
  125.     reader.close();   
  126.     return b.toString();   
  127.   }   
  128. }  

like查询

$sql=”select * from table_name where field_name like ‘%$var%'”;

  ·希望通过“标题”对新闻库进行检索,关键字可能包含是中英文,如

  下 SQL 语句:

  select id,title,name from achech_com.news where title like ‘%a%’

  返回的结果,某些 title 字段确定带了“a”关键字,而有些则只有中文,

  但也随之返回在检索结果中。

  解决方法,使用 BINARY 属性(二进制)进行检索,如:

  select id,title,name from achech_com.news where binary title like ‘%a%’

  返回的结果较之前正确,但英文字母区分大小写,故有时在检索如“Achech”

  及“achech”的结果是不一样的。

  知道了使用 BINARY 属性可以解决前面这个问题,再看看 MySQL 支持的

  UCASE 及 CONCAT 函数,其中 UCASE 是将英文全部转成大写,而 CONCAT 函

  数的作用是对字符进行连接,以下是我们完全解决后的 SQL 语句:

  select id,title,name from achech_com.news where binary ucase(title) like concat(‘%’,ucase(‘a’),’%’)

  检索的步骤是先将属性指定为 BINARY ,以精确检索结果,而被 like 的 title

  内容存在大小写字母的可能,故先使用 ucase 函数将字段内容全部转换成大

  写字母,然后再进行 like 操作,而 like 的操作使用模糊方法,使用 concat

  的好处是传进来的可以是直接的关键字,不需要带“%”万用符,将“’a’”直接

  换成你的变量,在任何语言下都万事无忧了。

  当然你也可以这么写:

  select id,title,name from achech_com.news where binary ucase(title) like ucase(‘%a%’)

  检索的结果还算满意吧,不过速度可能会因此而慢N毫秒喔。

上面方法是网上找来的,可能以后要用到,这里做个记录。。。

本文来自 长河日志 YL’S blog:http://www.lossr.net/read-1596.html

Mysql4安装Clientdoesnotsupportauthenticationprotocolrequested问题的解决

Mysql4安装Client does not support authentication protocol requested问题的解决

今天升级了一下Mysql数据库,结果出现了以下错误:
Client does not support authentication protocol requested by server; consider upgrading MySQL client

升级到4.1.7版:
[root@eygle gbook]# mysql -uroot -p -heygle
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 44 to server version: 4.1.7-max

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the buffer.

mysql>

查询了一下,在官方网站发现了解决方法:
http://dev.mysql.com/doc/mysql/en/Old_client.html

共有以下两种解决方法:

一:

mysql> SET PASSWORD FOR
-> ‘some_user’@’some_host’ = OLD_PASSWORD(‘newpwd’);

二:

mysql> UPDATE mysql.user SET Password = OLD_PASSWORD(‘newpwd’)
-> WHERE Host = ‘some_host’ AND User = ‘some_user’;
mysql> FLUSH PRIVILEGES;

使用第二种方法,解决了该问题。

MySQLServer5.0–安装及配置

下载软件:

MySQL Server 5.0.18 http://dev.mysql.com/downloads/mysql/5.0.html

下载MySQL Server,并安装在本地机器上。

下面两个为Windows图形界面工具。

MySQL Query Browser 1.1.20 http://dev.mysql.com/downloads/query-browser/1.1.html

MySQL Control Center 0.9.4 http://mysql.easynet.be/Downloads/MySQLCC/mysqlcc-0.9.4-win32.zip

配置MySQL步骤:

1.       运行MySQL Server安装目录下bin\MySQLInstanceConfig.exe。出现如下所示的向导界面  .

点击“Next”进入下一步。

2.       如果MySQLInstanceConfig在MySQL Server的安装目录下找到my.ini文件,就会询问:是重新配置MySQL还是删除MySQL service(同时删除my.ini文件)。

否则的话,出现下面的配置界面:

Detailed Configuration:自己配置大部分,更好地控制MySQL Server,让它更好地发挥作用。

Standard Configuration:系统配置大部分,不希望关注很多的Server配置。

这里选择“Detailed Configuration”,下一步(Next)。

3.       出现选择服务类型: 

Developer Machine:主要为了个人使用,占用系统最少的资源。

Server Machine:主要用于像FTP,email,web服务器等等,耗用系统较多的资源。

Dedicated MySQL Server Machine:只用作MySQL服务器,不运行其他程序。耗用系统所有可用的资源。

个人学习研究用,选“Developer Machine”,下一步(Next)。

4.       出现设置数据库用法: 

Multifunctional Database:使得InnoDB和MyISAM存储引擎都可用,且资源平分。

Transactional Database Only:使得InnoDB和MyISAM存储引擎都可用,但是InnoDB使用较多资源。

Non-Transactional Database Only:使InnoDB不可用,所有资源分配给MyISAM。

选择“Multifunctional Database”,下一步(Next)。

5.       设置InnoDB datafile存放位置,默认即可,下一步(Next)。

6.       出现选择并发连接设置对话框:

Decision Support(DSS)/OLAP:不需要大量的并发连接(20个左右)。默认值为100。

Online Transaction Processing(OLTP):需要大量的并发连接,默认值为500。

Manual Setting:个人设定了。

选择“Manual Setting”,从下拉框中选择10,下一步(Next).

7.       网络设定:

默认的端口号为3306,如果端口被占用或不希望使用3306,可以更换。下一步(Next)。

8.       选择缺省的字符集: 

Standard Character Set:Latin1为默认的字符集。主要用于西方欧洲国家的语言。

Best Support For Multilingualism:UTF8为默认的字符集。

Manual Selected Default Character Set / Collation:个人设定。(如果你希望数据库支持汉字,请选择gb2312)。

选择缺省的“Standard Character Set”,下一步(Next)。

9.       设置服务名称,最好将“Include Bin Directory in Windows PATH”勾选: 

10.    密码的设置,其余为默认: 

11.    执行,使配置生效。

配置过程中出现的问题:

1. 在最后一个环节,执行到第四步,出现如下所示的错误。

 

此时,按Skip跳出,再重新执行MySQLInstanceConfig,重复上次的选项,执行就可以通过了。

这个主要出现在remove instance之后。

2. Client does not support authentication protocol.

  工具连接数据库时,若出现上述信息,请到命令行方式下对密码进行转换:

mysql> SET PASSWORD FOR ‘root’@’localhost’ = OLD_PASSWORD(‘newpassword’);

4.1版本之后的密码采用 password hashing algorithm,有些工具连接数据库可能需要转换。

3. 连接MySQL服务器时,如果不是同一台PC机,出现连接不上。

   在“设置->控制面板->Windows 防火墙”,点击“例外”标签,“添加端口”后,出现:

  适当设置范围。端口号为先前设定的端口号。