public static void main(String[] args) throws Exception { Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1/hive", "test", "123"); String sql = "SELECT * FROM v"; //1 PreparedStatement ps = c.prepareStatement(sql); ResultSet rs = ps.executeQuery(); //2 javax.sql.rowset.CachedRowSet crsi = new com.sun.rowset.CachedRowSetImpl(); crsi.setCommand(sql); crsi.execute(c); }
SUN私有包已不被甲骨文支持,因此不推荐使用该实现类 CachedRowSetImpl,
分隔符【//2】下面的部分在MySQL5.1及以下版本执行跨库视图查询时会报错(在5.5正确):
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: SELECT command denied to user 'test'@'127.0.0.1' for table 'v'
为什么用标准的Statement不会报错,而用SUN的遗物却会出错?是否用户test没有查询视图v的权限呢?
参考:ALTER VIEW语法,以下内容摘自CREATE VIEW语法
If you specify the DEFINER clause, these rules determine the legal DEFINER user values:
如果指定了DEFINER子句,就由这些规则来决定视图定义者的值:
If you do not have the SUPER privilege, the only legal user value is your own account, either specified literally or by using CURRENT_USER. You cannot set the definer to some other account.
如果你的帐户没有super权限,那唯一可以指定的合法用户就是你自己,无论是指定CURRENT_USER还是全称。
If you have the SUPER privilege, you can specify any syntactically legal account name. If the account does not actually exist, a warning is generated.
如果你有super权限,那你可以指定任何用户为DEFINER。如果该用户不存在,则会有一个警告。
Although it is possible to create a view with a nonexistent DEFINER account, an error occurs when the view is referenced if the SQL SECURITY value is DEFINER but the definer account does not exist.
尽管可以指定一个错误的用户为定义者,但是如果同时SQL安全检测设置为DEFINER级别时引用该视图的时候会报错。
上文提到了视图的SQL安全检测机制,第三点中说到,如果指定了不存在的视图定义者,那么该视图可能会执行出错,参看下面的例子:
-- login as root GRANT SELECT ON hive.* TO 'test'@'%' IDENTIFIED BY '123'; USE HIVE CREATE VIEW v AS SELECT * FROM hue.auth_group; SHOW CREATE VIEW v\G -- Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `hue`.`auth_group`.`id` AS `id`,`hue`.`auth_group`.`name` AS `name` from `hue`.`auth_group` ALTER DEFINER=t@'%' VIEW v AS SELECT * FROM hue.auth_group; -- user t not exist SHOW WARNINGS; -- +-------+------+----------------------------------------------------------+ -- | Level | Code | Message | -- +-------+------+----------------------------------------------------------+ -- | Note | 1449 | The user specified as a definer ('t'@'%') does not exist | -- +-------+------+----------------------------------------------------------+ ALTER DEFINER=t@'%' SQL SECURITY DEFINER VIEW v AS SELECT * FROM hue.auth_group; SELECT * FROM v; -- ERROR 1449 (HY000): The user specified as a definer ('t'@'%') does not exist ALTER DEFINER=t@'%' SQL SECURITY INVOKER VIEW v AS SELECT * FROM hue.auth_group; -- ok ALTER DEFINER=test@'%' VIEW v AS SELECT * FROM hue.auth_group; -- ERROR 1356 (HY000): View 'hive.v' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them ALTER DEFINER=test@'%' SQL SECURITY DEFINER VIEW v AS SELECT * FROM hue.auth_group; -- error still ALTER DEFINER=test@'%' SQL SECURITY INVOKER VIEW v AS SELECT * FROM hue.auth_group; -- fine
上面这个栗子中间为什么会报错呢?指定SQL Security后对语句执行又有什么影响?以及,为什么要制定一个额外的安全检测机制呢?
参考mysql存储过程权限相关,以下内容摘自Access Control for Stored Programs and Views:
DEFINER和SQL SECURITY是标准SQL的扩展。标准SQL中定义视图的定义者即是视图的语句拥有者,
但是MySQL中其实并没有“语句拥有者”这一说法,因此需要额外定义一个权限来控制视图的执行检测。
实际上视图的定义者默认就是创建视图的人。在MySQL5.0.16之前的版本这两个属性是无效的。以下内容译自官方文档:
Definer and invoker security contexts differ as follows:
Definer和invoker两者对安全环境检测的区别如下:
A stored program or view that executes in definer security context executes with the privileges of the account named by its DEFINER attribute.
存储过程(或视图)在definer安全上下文中执行所需的权限只与定义者属性指定的用户权限相关(比如root定义了definer安全模式的跨库视图,即使其他用户没有跨库权限也可正确执行该视图)。
A stored routine or view that executes in invoker security context can perform only operations for which the invoker has privileges. The DEFINER attribute can be specified but has no effect for objects that execute in invoker context.
过程或视图在invoker模式下执行时会检测存储过程内部语句(或视图定义)的执行权限(比如跨库视图,会检测当前执行用户是否有对应库的相应权限)。此时,视图定义者这一属性不再生效。
简单来说(引用自全面学习MySQL中的视图(1) 视图安全验证的方式):
definer是在定义对象是判断是否有权限,只要创建的用户有权限,那么创建就可以成功,而且所有有权限查询该视图的用户也能够成功执行查询语句 - 不管是否拥有该视图所引用对象的权限
invoker是指在查询时验证用户是否有权限执行操作,当然创建时也会判断,如果创建的用户没有视图所引用表对象的访问权限,那创建都会失败
我们都知道MySQL的timestamp相对datetime类型占用字节较小,但是时间范围暂时受限,
不仅如此,一张表中还支持最多一个自动更新时间戳的timestamp字段。
由于MySQL目前还不支持函数作为默认值,因此datetime无法实现这一点。但是它有一个很大的弊端:时间受时区影响。
同样的,Java程序中的Date类及其子类也受时区影响。我们再来看一个栗子:
public static void main(String[] args) throws Exception { Date d = new Date(); System.out.println(d); String file = "c:/crs.oos"; TimeZone timezone = TimeZone.getDefault(); // 将时间对象序列化写入文件 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(d); oos.flush(); oos.close(); // 修改JDK系统默认时区 timezone.setRawOffset(-36000000); TimeZone.setDefault(timezone); // 反序列化从文件读取时间对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); Date d1 = (Date) ois.readObject(); ois.close(); System.out.println(d1); }
执行上面的程序会发现时间变了(序列化的目的是为了更形象的表示之前的时间是固定不变的)。
为什么写入文件的时间再次读取后变了呢?
其实Java中Date的实现与MySQL中timestamp的实现是类似的。解决的方法也大同小异:
-- 转成unixtimestamp后传输,然后再转回datetime SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(NOW())); -- 转成字符串传输 SELECT CAST(NOW() AS CHAR(20));
转成字符串后无需额外处理,只要转回Date类型即可,若是直接传输的Date类,则需要进行时区转换。
// timezone指目标主机与当前主机的时区差 public static Object getObject(int index, int timezone, CachedRowSet crs) throws Exception { int type = crs.getMetaData().getColumnType(index) if (java.sql.Types.DATE == type) return crs.getDate(index); else if (Types.TIME == type)// 必须转换时区 return crs.getTime(index, Calendar.getInstance(TimeZone.getTimeZone("GMT+" + (8 + timezone)))); else if (Types.TIMESTAMP == type) { if (timezone == 0) return crs.getTimestamp(index); Timestamp times = crs.getTimestamp(index, Calendar.getInstance(TimeZone.getTimeZone("GMT+" + (8 + timezone)))); times.setNanos(0); return times; } else if (Types.CHAR == type || Types.VARCHAR == type || Types.NCHAR == type || Types.NVARCHAR == type) { return crs.getString(index); } else return crs.getObject(index); }
参考:Java TimeZone
MySQL 去除字段中的换行和回车符:
UPDATE tb SET field=REPLACE(REPLACE(field,CHAR(10),''),CHAR(13),'')
char(10): 换行符;char(13): 回车符;TRIM():去除空格
mysql 表的多列交叉去重问题
MySQL排序规则:MySQL也有潜规则 – Select 语句不加 Order By 如何排序?,MySQL修改默认排序:
ALTER TABLE tb ORDER BY field DESC
MySQL int(11)和int(3)的区别,只有加了zerofill才有显示长度的区别,实际都是占用4个字节。