数据库MySQL与Oracle的一些去O注意项
一、oracle递归查询语句start with ...connect by prior
① 给你一张表,表里面有主键id,以及该项的父节点parent_id,查询出该表中所有的父子关系节点树?
Oracle: start with ...connect by prior
例如:对分类下的所有组图(包括子分类下的组图)列表进行分页
select g.* from t_group g, t_counter c where g.counter_id = c.id and g.category_id in ( select id from t_category start with id = ? connect by prior id = parent_id and status = 1) and status = 1 order by c.pv desc
mysql:没有oracle那种自带的查询参数,在java端写递归函数,或者递归的存储过程
递归查找某一分类下的所有子分类,数据表结构如图
CREATE TABLE t_category (
category_id int() unsigned NOT NULL COMMENT '栏目id,主键',
parent_id int() unsigned COMMENT '分类父类id',
original_parent_id int() unsigned COMMENT '原始父类id,放到垃圾箱保留原有从属关系',
name varchar() COMMENT '名称',
code varchar() COMMENT '编码',
...
status int() COMMENT '状态;0: 草稿, 1: 通过(发布), -1: 删除',
...
)
java解决方案:
public void getAllChildren(long categoryId, int status, List<Long> categoryIdList) {
List<Long> childrenIds = getCategoryChildrenIds(categoryId, status);
for (long cateId : childrenIds) {
categoryIdList.add(cateId);
int count = geliDao.count("select count(1) from t_category where parent_id = ? and status = ?", cateId, status);
if (count > ) {
getAllChildren(cateId, status, categoryIdList);
}
}
}
在要使用该递归函数的地方,该这样使用
public Pager<Group> findGroupByCateAndName(long categoryId, String name, int pageNo, int pageSize) {
SqlBuilder sqlBuilder = new SqlBuilder();
sqlBuilder.appendSql("select group_id from t_group where category_id in ");
List<Long> routeIds = new ArrayList<Long>();
routeIds.add(categoryId);
getAllChildren(categoryId, Category.STATUS_NORMAL, routeIds);
sqlBuilder.appendValues(routeIds.toArray());
if(StringUtils.isNotBlank(name)) {
sqlBuilder.appendSql(" and name like ");
sqlBuilder.appendValue("%" + name + "%");
}
sqlBuilder.appendSql(" order by group_id desc");
LOG.debug("findGroupByCateAndName : {}; {}", sqlBuilder.getSql(), sqlBuilder.getValues());
return new Pager<Group>(sqlBuilder.getSqlExt(), sqlBuilder.getValuesExt(), pageNo, pageSize);
}
二、oracle函数decode处理
在Oracle/PLSQL中, decode 具有和 IF-THEN-ELSE 一样的功能。
decode 函数语法如下:
decode( expression , search , result [, search , result]... [, default] )
expression 要比较的表达式.
search 要与expression 比较的字段。.
result 如果expression 与search 一样的话,返回该结果。.
default 此参数可选,如果没有与expression 匹配上的search . 就返回此结果,如果此参数没有设置,当没有与expression匹配上的search时,返回null。
search 和 result可成对出现多次,代表各种要匹配的情况。
sign(number) 函数返回一个数字的正负标志.
问题1: 现在一个阅读者想问,怎么使用decode函数来比较两个日期呢?(例如:date1 和 date2), 如果date1 > date2, decode 函数返回date2. 否则decode函数返回 date1.
可用decode函数绑定SIGN 函数 像下面这样:
上面比较日期的语句可修改如下:
DECODE(SIGN(date1-date2), 1, date2, date1)
eg:如果有app参数就查询该app对应的指令数目,否则查询所有指令数目
public long searchCommandCount(String app)
{
if(app == null) app="";
String sql = "select count(0) "+
"from t_command a,t_application b where a.applicationid=b.id and b.application = decode(?,'',b.application,?) ";
return simpleJdbcTemplate.queryForLong(sql, app, app);
}
mysql处理后
public long searchCommandCount(String app)
{
if(app == null) app="";
StringBuilder sb = new StringBuilder();
sb.append("select count(0) from t_command a,t_application b where a.applicationid=b.id");
if(!"".equals(app)){
sb.append(" and b.application = "+ app);
}
/*String sql = "select count(0) "+
"from t_command a,t_application b where a.applicationid=b.id and b.application = decode(?,'',b.application,?) ";*/
return simpleJdbcTemplate.queryForLong(sb.toString());
}
三、oracle自增长序列处理
关于SEQUENCE 的基本知识请参考ORACLE SEQUENCE用法
原处理方案:
CREATE SEQUENCE SEQ_TONY_APK_ID MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1976634 CACHE 20 NOORDER NOCYCLE ;
//获取id
public long createTonyId()
{
return simpleJdbcTemplate.queryForLong("select seq_tony_apk_id.nextval from dual");
}
mysql解决方案:
普通的可能会想到用mysql的自增长auto_increament,不过这个在数据库做分库分表的时候,有可能出问题,具体原因请参照数据库分库分表(sharding)系列(二) 全局主键生成策略
使用全局主键表
CREATE TABLE gl_keygen(
table_name varchar() NOT NULL COMMENT '表名,主键',
last_used_id int() unsigned NOT NULL COMMENT '最后使用的id'
) ENGINE= InnoDB DEFAULT CHARSET=gbk;
我们使用一个Java类来控制某一字段自增长
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map; import javax.sql.DataSource; public class IdTableGenerator {
DataSource idGenDataSource; public void setIdDataSource(DataSource idGenDataSource) {
this.idGenDataSource = idGenDataSource;
} int size = ; Map<String, IdHolder> holderMap = new java.util.concurrent.ConcurrentHashMap<String, IdHolder>(); public long generate(String tableName, String columnName) {
IdHolder holder = holderMap.get(tableName);
if (holder == null) {
holder = new IdHolder();
holderMap.put(tableName, holder);
}
synchronized (holder) {
if (holder.needAlloc()) {
long lastUsedId = alloc(tableName, columnName, size);
holder.currentId = lastUsedId + ;
holder.limit = lastUsedId + size;
} else {
holder.currentId ++;
} return holder.currentId;
} } static class IdHolder {
long currentId;
long limit;
boolean needAlloc() {return currentId >= limit; }
} public long alloc(String tableName, String columnName, int size) {
long result = ;
Connection con = null;
boolean oldAutoCommit = false;
try {
con = idGenDataSource.getConnection();
oldAutoCommit = con.getAutoCommit();
con.setAutoCommit(false);
int updateCount = updateLastUsedId(con, tableName, columnName, size); if (updateCount == ) {
initIdTable(con, tableName, columnName);
}
result = getLastUsedId(con, tableName, columnName); con.commit();
} catch (Exception e) {
try {
con.rollback();
} catch (Exception ex) {
ex.printStackTrace();
}
throw new RuntimeException(e);
} finally {
if (con != null) {
try {
con.setAutoCommit(oldAutoCommit);
con.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
} return result;
} static long getLastUsedId(Connection con, String tableName, String columnName) throws SQLException {
PreparedStatement ps = con.prepareStatement("select LAST_USED_ID from GL_KEYGEN where table_name = ?");
ps.setString(, tableName);
ResultSet rs = ps.executeQuery();
rs.next();
long result = rs.getLong();
rs.close();
ps.close();
return result;
} static int updateLastUsedId(Connection con, String tableName, String columnName, int size) throws SQLException {
PreparedStatement ps = con.prepareStatement("update GL_KEYGEN set last_used_id = last_used_id + ?" +
" where table_name = ?"); ps.setInt(, size);
ps.setString(, tableName); int result = ps.executeUpdate();
ps.close();
return result;
} static void initIdTable(Connection con, String tableName, String columnName) throws SQLException {
PreparedStatement ps = con.prepareStatement("select max(" + columnName + ") from " + tableName);
ResultSet rs = ps.executeQuery();
rs.next();
long maxId = rs.getLong();
rs.close();
ps.close(); ps = con.prepareStatement("insert into GL_KEYGEN (table_name, last_used_id) values (?, ?)");
ps.setString(, tableName);
ps.setLong(, maxId);
ps.executeUpdate();
ps.close();
} }
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/test"/>
<bean id="idGenerator" class="cn.tony.repository.IdTableGenerator" p:idDataSource-ref="dataSource"/>
数据源配置
<database>
<jndi-name>jdbc/test</jndi-name>
<driver type="com.mysql.jdbc.Driver">
<url>jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=GBK&zeroDateTimeBehavior=convertToNull
</url>
<user>root</user>
<password>root</password>
</driver>
<prepared-statement-cache-size></prepared-statement-cache-size>
<max-connections></max-connections>
<max-idle-time>30s</max-idle-time>
</database>
主键自增生成器使用案例:
public abstract class AbstractRepository <T> {
@Autowired
IdTableGenerator idGenerator; protected long getNextId(String tableName, String columnName){
return idGenerator.generate(tableName, columnName);
} //默认使用id做主键
protected long getNextId(String tableName){
return idGenerator.generate(tableName, "id");
} } public class TonyRepository extends AbstractRepository<Tony> {
public long createTonyId(){
return getNextId(Tony.TABLE_NAME);
}
}
四、其他函数
to_date---> str_to_date
(yyyy-MM-dd HH24:mi:ss) --- (%Y-%m-%d %H:%i:%s)
sysdate --->sysdate()
to_char --->mysql中没有对应的函数,MySQL必要时自动变换数字为字符串
mysql中key 、primary key 、unique key 与index区别
Oracle的to_date函数
五、SQL中特殊符号处理
用字符串拼接的话,单引号必须经过判断并替换,在数据库中,用2个单引号代表1个实际的单引号。所以,如果是拼接方式,需要用String.Replace("’", "”")来替换一下,将1个单引号替换为2个就没有问题了。在模糊查询中,为了避免单引号,我们使用参数的方式,下面的语句是不对的:
SELECT * FROM yourTable WHERE name LIKE ‘%?%’;在这个句子中,’%?%’被整体当作一个字符串来处理,你无论如何查询不到结果。修改一下,SELECT * FROM yourTable WHERE name LIKE ?;然后添加参数的时候这么添加:
new Parameter("?", "%" + categoryName + "%");
通配符_ % 处理
如果用户输入的查询条件中含有通配符,必须将这些字符作为数据而不是通配符来对待
s = s.Replace("%", "[%]");
s = s.Replace("_", "[_]");
左方括号([)问题
如果用户输入的查询参数本身就包括方括号时,会出现什么结果呢?
根据用户的期望,如果输入一个方括号,查询结果中应该只包括那些字段值中含有方括号的记录。
但是实验结果表明,如果是没有配成对的单个左方括号,查询时这个左方括号会被忽略。
也就是说,下面这个语句:
WHERE T2.name like (%+ [ + %)
等价于下面这个语句:
WHERE T2.name like (%+ + %)
这将导致查询结果中包含表中的全部记录,就像没有任何过滤条件一样。
为此,如果用户输入的查询条件中含有左方括号的话,还必须对左方括号进行转义:
s = s.Replace("[", "[[]");
注:右方括号没有这个问题。
结论
为了防止SQL注入,同时避免用户输入特殊字符时查询结果不准确的问题,应该做两件事:
(1)使用参数化查询。
(2)在使用用户输入的字符串数据设置查询参数值之前,首先调用下面的共通处理函数:
private static string ConvertSql(string sql) {
sql = sql.Replace("[", "[[]"); // 这句话一定要在下面两个语句之前,否则作为转义符的方括号会被当作数据被再次处理
sql = sql.Replace("_", "[_]").Replace("%", "[%]");
return sql;
}
数据库MySQL与Oracle的一些去O注意项的更多相关文章
- Sqoop是一款开源的工具,主要用于在HADOOP(Hive)与传统的数据库(mysql、oracle...)间进行数据的传递
http://niuzhenxin.iteye.com/blog/1706203 Sqoop是一款开源的工具,主要用于在HADOOP(Hive)与传统的数据库(mysql.postgresql.. ...
- 了解常用数据库MySQL、Oracle、MongoDB
本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net 注:转载文章 什么是数据库 简单的说,数据库(英文 Dtabase)就是一个存放数据的仓库,这个仓库是按照一定的数据结果( ...
- jboss7.1.1配置数据库mysql与oracle
环境: joss7.1.1安装成功,路径为:D:\profession\jboss-as-7.1.1.Final mysql-connector-java-5.1.18-bin.jar(mysql 5 ...
- 如何查询数据库中所有表格,或者查询是否存在某个表格-mysql和oracle
这个问题,在之前就有写过,但是想找到语句还是记不得,这里主要提及我自己有用到的数据库mysql和oracle 1.mysql 这个是自己安装的,所有配置都是默认配置没有改变,所以保存表名的表还是inf ...
- Java学习-006-三种数据库连接 MySQL、Oracle、sqlserver
此文主要讲述在初学 Java 时,常用的三种数据库 MySQL.Oracle.sqlserver 连接的源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源 ...
- 基于Hadoop(M/R)的MySQL到Oracle海量数据切割
# 背景介绍 大数据时代,海量数据的迁移会很普遍地出现在各个应用场景,本文主要讨论利用Sqoop的分布式能力从关系型数据库MySQL到Oracle的海量数据迁移和切割. # 所需环境 1 JDK+Ec ...
- 数据库-mysql命令
1.项目过程:概要设计阶段 —— 架构师 任务:技术选型(网络/语言/框架).项目结构(子系统/模块).数据结构(数据特点/内容) 项目中存储数据的方式: (1)服务器内存:存取速度快:非永久存储.容 ...
- 数据库 MySQL 之 基本概念
数据库 MySQL 之 基本概念 浏览目录 概述 数据库的特点 数据库的分类 选择MySQL的理由 & MariaDB 介绍 下载及安装 SQL介绍 一.概述 1.数据(data) 存储在表中 ...
- Jsp 连接 mySQL、Oracle 数据库备忘(Windows平台)
Jsp 环境目前最流行的是 Tomcat5.0.Tomcat5.0 自己包含一个 Web 服务器,如果是测试,就没必要把 Tomcat 与 IIS 或 Apache 集成起来.在 Tomcat 自带的 ...
随机推荐
- windows server 开机自动登录并锁定
这个操作对于广大使用Windows(包括xp/win7/2003/2008 R2 等windows 系统) 的上班族会有点用. 其一:如果是个人吧系统(win7.xp)上班时候打开电脑,自动登录,系统 ...
- Java中的内部接口
什么是内部接口 内部接口也称为嵌套接口,即在一个接口内部定义另一个接口.举个例子,Entry接口定义在Map接口里面,如下代码: public interface Map { interface En ...
- [整理]PHP/HTML混写的四种方式
PHP作为一款后端语言,为了输出给浏览器让浏览器呈现出来,无可避免的要输出HTML代码,下文介绍下我用过的三种PHP/HTML混编方法 1.单/双引号包围法 这是最初级的方法了,用法就像下面这样 &l ...
- 字符集GBK升级UTF8
在生产环境中,数据库字符集因为各种原因需要升级,比如为了支持汉字,从latin1字符集升级到GBK,后面为了支持多个语言文字,需要将GBK升级到UTF8等.迁移过程网上有很多,我今天主要想讲下字符集转 ...
- hibernate 实现分页查询语句、单条查询语句、多条查询语句、修改、删除语句
package com.hanqi.test; import java.util.Date; import java.util.List; import org.hibernate.Query; im ...
- Linux 多线程互斥量互斥
同步 同一个进程中的多个线程共享所在进程的内存资源,当多个线程在同一时刻同时访问同一种共享资源时,需要相互协调,以避免出现数据的不一致和覆盖等问题,线程之间的协调和通信的就叫做线程的同步问题, 线程同 ...
- 举例讲解Linux系统下Python调用系统Shell的方法
有时候难免需要直接调用Shell命令来完成一些比较简单的操作,比如mount一个文件系统之类的.那么我们使用Python如何调用Linux的Shell命令?下面来介绍几种常用的方法:1. os 模块 ...
- [转载]利用@media screen实现网页布局的自适应,@media screen and
开始研究响应式web设计,CSS3 Media Queries是入门.Media Queries,其作用就是允许添加表达式用以确定媒体的环境情况,以此来应用不同的样式表.换句话说,其允许我们在不改变内 ...
- C 结构体位域
位域 : 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可.为了节省存储空间,并使处理简便,C语言又提供了一 ...
- Java:JSTL遍历数组,List,Set,Map
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...