mysql中错误码1406 data too long在jdbc和命令行的不同表现及处理

2016/07/04 21:56:03 No Comments

今天在同事开发过程中碰到一个mysql的错误码:1406,显示的错误信息为 data too long for column,而导致相应的事务被回滚.将此错误码(google 关键字 mysql 1406),即搜索到相应的错误信息,即相应的插入数据比实际的列的大小更大.然后,报相应的错误信息,最终处理失败.

但是,对于这条sql语句,如果将语句贴到命令行去执行,即得到另外一个结果.sql不会报错,但再次查询相应的数据信息,会发现插入的数据被自动截断了.在这种情况下,实际上插入的数据是错误的,即因为不同的行为得到不同的结果.

然后,再次google(关键字 mysql自动截断)会发现这两种情况是因为使用了不同的sql_mode导致.获取相应的sql_mode命令可以如下所示(笔者mysql为mariadb 10.1)

select @@sql_mode;

获取的数据信息为:NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION.

这种情况下,即会产生自动截断的设置.可以通过set @@sql_mode="xxx"来修改.影响截断地设置为 strict_trans_tables 或者 strict_all_tables.将其设置为其中之一即可.

反之,使用默认的jdbc连接mysql时,同样通过命令获取相应的数据,结果为
NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
会发现相应的设置并不与命令行相同.

这里的原因在于,在mysql的jdbc驱动中,之前也是与命令行相同,但为了保证与jdbc规范相符(具体的规范没找到),引入了配置变量 jdbcCompliantTruncation.此变量可以在连接字符串中,追加并设置为false.其默认值为true.
在具体的mysql jdbc实现中(当前版本为5.1.39),此变量会在类ConnectionImpl中判定.如果为true,并且版本大于5.0.2,则会发语句set sql_mode=xxx 来进行重新设置.其重新设置的值,即在之前提到值的基础之上,追加值 STRICT_TRANS_TABLES. 然后,在此设置的影响下,插入数据超长即会直接报错,而不是自动截断.

read more… »

服务端推送websocket和sse场景及应用

2016/07/04 14:21:44 No Comments

在当前的系统中, 涉及到使用长连接进行通信的应用越来越多,许多应用场景也已经不再满足于通过常规的http来进行短时间的交互.而是希望像传递的cs结构一样,常时间地挂在服务器上,以接收一定的数据信息.可以理解为使用浏览器来作传统cs客户端的事情.

经过几天简单地了解,就当前使用java进行后端推送类的服务进行了一些了解,就应用场景,开发方式以及一些特定的实现进行了简单的demo处理.

应用场景

  1. 都可以进行服务端推送,并且都是使用长连接来进行.但两者的实现又有一点不同,sse仍使用http协议,并且使用相同的链接发送正常的http协议报文.而websocket是使用http协议进行握手,然后再使用同一个链接进行websocket协议的通信.
  2. websocket可以进行双向的通信,即服务端可以往客户端发信息,客户端也可以向服务端发信息.而sse是单向的,只能由服务端往客户端发.
  3. websocket自带连接的保持,即通过ping/pong协议保证连接可以始终维持,sse没有这个保证,不过可以参考ping/pong协议,自己周期性地发送信息来同样地进行处理.比如,5秒往客户端发一个特别的信息(通过type/name进行区分).其次,因为是基于浏览器的使用,sse有一个特性,就是浏览器发现一个连接断掉了,就会自动地进行重联,即重新发送请求.这样,服务端也不用担心连接被断开,不过需要处理新的请求必须和上一次请求的内容相连续,以及新的推送注册.
  4. 因为都是使用http协议进行起始处理,因此在签权上都可以使用到http协议本身的一些东西,比如header/cookie签权.在相应的握手阶段,通过读取cookie(session)来保证相应的请求必须是经过授权的,也可以用于定位使用人.甚至可以通过这些信息保证单个用户只能有一个请求,避免重复请求
  5. 由于都是基于浏览器使用,因此建议的数据传输都是文本型.虽然websocket支持二进制frame传输,不过一些都不建议使用.sse只能传输文本
  6. 不管是websocket还是sse,在用于通信时,都建议只用于进行数据的推送,而不是进行完整的应用处理.这里可以理解为,常规的业务处理仍然交给后端的服务来处理.这样,即可以使用之前的业务开发的优势,又可以使用推送的优势.而不是走向另一个级端,即所有的信息都想通过推送来传递.

read more… »

开发可正确序列化和反序列化的guava table组件

2016/06/20 15:32:17 No Comments

首先,什么是Table,可以理解为前端使用的html table组件,它具有行头,列头,以及具体的数据.即描述有多少行,多少列,在行为X,列为Y的二维格子中所对应的值是多少.

在使用google guava组件同时,也在讨论其组件的一些局限性,比如它的不变性,对序列化支持的不友好等.
其中table就是一个例子,作为一个表格组件的后端对应数据结构,其自带的table实现完全不能满足实际的需要.其大部分实现都是不可变的,即意味着必须要使用类似builder的模式来进行创建,一旦创建好之后,就不能再次修改.那么,作为一个实际可用的table实现,它需要哪些特性呢.以下例出我们所需要的要求:

1. 查找 按行,按列,快速定位
2. 快速迭代,按行,按列,支持稀疏迭代
3. 泛型支持(通用化)
4. 支持排序
5. 行,列动态增长,削减
6. 反序列化支持(json)

也就是说,我们期望像使用java的集合一样,创建出相应的数据之后,一直都是可变的,并且可以随意地进行传递,然后再任意地进行处理.无论按行,按列,都能够很好地使用.
本篇即描述了如何实现这样一个table组件,以及它最终的效果.

已实现的github地址:https://github.com/flym/array-tree-table

read more… »

使用nod32导致客户端响应中没有gzip压缩标识的问题

2016/06/20 11:18:58 No Comments

之前在本机研究dropwizard时,本着默认的情况下应该开启gzip压缩,因此在相应的yml配置中开启gzip标记(它本身也是开启的).但是在相应的请求返回中并没有出现相应的gzip标识,在chrome浏览器下的标识信息为如下的响应所示:

从上面的标识来看,在响应头上并没有gzip标识.
然后开始痛苦的处理过程,从浏览器,客户端,服务端,然后最后从网络层逐步处理,最终找到问题的原因及出处.

read more… »

haproxy和keepalived的个人理解

2016/05/16 21:35:48 No Comments

附参考文:http://weizhifeng.net/HA-with-HAProxy-and-KeepAlived.html

关于此两者,随便google一下都会有大量的文章,因此这里也不用介绍如何来进行安装和配置了。主要从一个整体方案的角度来描述什么要这样做,以及这样做所解决的问题。

所有的系统,都是先经历一个单台机器搞所有业务的时代,一个程序+一个mysql数据库,就可以满足开发及第一个版本上线的要求。随着,数据的增加以及业务的增长,这些应用就面临一个访问量的扩大以及扩展的问题。最简单的扩展就是水平扩展,原来由一个mysql增加为2个或多个,形成一个集群,这样最简单的能力就是提供更强的服务能力。如原来的访问量支持每秒1000,现在可以支持2000(理想值),相当于将服务能力分散到多个节点。
这里面涉及到多个问题,首先就是数据的相互备份,然后就是如何分配计算能力,外部如何来访问等。本文引入HaProxy和KeepAlived主要处理的就是一个外部访问问题。

在后面的介绍当中,假定有2个mysql,分别为mysqlA和mysqlB.

read more… »

获取java代码中方法的参数名信息

2016/04/28 20:25:46 No Comments

随着java8的使用,在相应的方法签名中增加了新的对象Parameter,用于表示特定的参数信息,通过它的getName可以获取相应的参数名.即像在代码中编写的,如命名为username,那么在前台进行传参时,即不需要再编写如@Parameter("username")类的注解,而直接就能进行按名映射.
如下的代码参考所示:

public class T {
    private interface T2 {
        void method(String username, String password);
    }

    public static void main(String[] args) throws Exception {
        System.out.println(T.class.getMethod("main", String[].class).getParameters()[0].getName());
        System.out.println(T2.class.getMethod("method", String.class, String.class).getParameters()[0].getName());
        System.out.println(T2.class.getMethod("method", String.class, String.class).getParameters()[1].getName());
    }
}

按java8之前,也可以通过一些手段拿到参数名信息,只不过方式不同而已.如通过spring mvc中的ParameterMethodNameResolver在之前的版本中也可以正常工作.不过需要特别的编译而已.这里面起作用的即是 LocalVariableTable 和 MethodParameters,中文编译为本地变量表和方法参数表.

read more… »