有一个使用了不同数据库的应,Oracle 和 PostgreSQL,数据库中的记录完全相同,相同的查询语句(相同的排序,至少从字面上来说是的)取到的记录排序却不同,从而产生了 Bug。 简单演示一下默认排序各自在这两种数据库中的行为, 比如说表中有两条记录,'VFORX' 和 'ibbVA'。此处不创建物理表。
Oracle(Linux)select * from (
返回的结果是 Read More
select 'VFORX' as value from dual
union
select 'ibbVA' from dual
) order by 1 desc;
这段时间都纠缠于 Java 如何操作 PostgreSQL 数据库上,千方百计的为求得更好的性能。为此我们用上了 Batch, 或用 id = any(?) 这种更 PostgreSQL 化的数组参数操作。其实它还有更多数组方面的花样可以玩,毕竟 PostgreSQL 数据库有一种广纳百川的胸怀,总有好的新特性能在 PostgreSQL 中首先体验到。
回到之前的一篇 postgres in (?,?) 和 =any(?) 用法/性能对比,其中关于如何向查询语句中
id = any(?)占位符传入数组参数的代码是1Connection conn = datasource.getConnection(); 2 3String query = "select * from users where id = any(?)"; 4PreparedStatement pstmt = conn.prepareStatement(query); 5Object[] params = new Object[]{1, 2, 3}; 6pstmt.setArray(1, conn.createArrayOf("int", params)); 7ResultSet rs = pstmt.executeQuery();在 PreparedStatement(PgPreparedStatement) 中设置数组参数的函数是用 Read More
- 继续上一篇数据库相关操作的话题,在有大量的数据操作时(如增删改,甚至调用函数或存储过程),我们应该尽可能的采用批量化操作(先摆下结论,后面我们会看到原由)。想像一下我们要向数据库插入 10 万条记录,如果逐条插入的话,客户端与数据库之间将会有 10 万网络请求响应来回; 而假如以 1000 条记录为一个 batch, 客户端与数据库之间的网络请求响应次数将缩小到 100。 业务数据的内容总量未变,但 Batch 操作除了可重用预编译的 Statement 外还, 可避免每次请求中重复的元数据,所以从 100,000 到 100 的缩减在时效上的表现是非常可观的,有时就是 60 分钟与 1 分钟的区别(在最后面测试结果显示这一差异更为恐怖)。
当然, JDBC 的批处理功能具体还要相应驱动的支持,通过数据库连接的 conn.getMetaData().supportsBatchUpdates() 可探知是否支持批量操作。
API 方面, 在 Statement 接口中定义了如下 batch 相关的操作方法- void addBatch(String sql): 将显式的 SQL 语句编入到当前 Batch 中
- void clearBatch(): 清除当前 Batch 列表,以便于建立新的 Batch
- int[] executeBatch(): 执行当前 Batch 列表中的语句,返回每条语句受影响行数组成的数组。0 可能表示执行语句无法确知受影响的行
- long[] executeLargeBatch(): 当 Batch 中语句受影响行数可能会超过整数最大值时用这个
PostgreSQL 随着云服务的盛行,越发被广泛的应用,免费开源且有丰富的特性支持,加上性能也很不错,因而备受青睐。PostgreSQL 的函数与存储过程区别并不太大,不像某些数据库的函数与存储过程必须是无副作用或有副作用,在 PostgreSQL 的函数和存储过程中可以进行任何的 SQL 操作。简单列举下 PostgreSQL 的函数与存储过程的区别主要如下:
函数- return 或 out 参数返回值,return 可返回单个值或一系列值(return setof 或 return table), 或返回光标(cursor). 函数 return void 就和存储过程差不多了
- 函数因其有返回值,所以可通过 select, insert, updata 或 delete 语句来调用,如 select fn1(), delete * from test1 where fn2(c1)=0
- 可以用 execute 执行动态 sql, 如 execute 'delete * from ' || 't1'
存储过程- IN, OUT 或 INOUT 参数,但不直接返回值
- 不能用 select, insert 等语句使用
- 不能用 execute 执行动态 sql
接下来我们来体验一下 PostgreSQL 的函数与存储过程 Read More
刚刚回顾了一下 JDBC 操作 SQL Server 时如何传入列表参数,即如何给 in (?) 条件直接传入一个列表参数,然而本质上是不支持,最终不得不展开为 in (?, ?,...?) 针对每个元素单独设置参数,不定长的参数对于重用已编译 PreparedStatement 语句的帮助不大。
那么 JDBC 操作 PostgreSQL 是何种状态呢?展开为多个参数当然是有效的。继续尝试 Spring 提供的 NamedParameterJdbcTemplate 的操作方式
String query = "select * from users where id in (:ids)";
Map<String, Object> parameters = new HashMap<>();
parameters.put("ids", IntStream.rangeClosed(1, 5).boxed().collect(toList()));
List<Map<String, Object>> maps = namedParameterJdbcTemplate.queryForList(query, parameters);执行后查看到实际执行的语句是
select * from users where id in (?, ?, ?, ?, ?)
Read More
本文是作为将要对 PostgreSQL 的 in, any() 操作的一个铺垫,也是对先前用 JDBC 操作 SQL Server 的温习。以此记录一下用 JDBC 查询 SQL Server 时如何传递一个列表参数。比如想像一下查询语句
select * from users where id in (?)
我们是否能给这里的问题参数传递一个 List 或数组呢?
这里所引用的 SQL Server 的 JDBC 驱动是 com.microsoft.sqlserver:mssql-jdbc:11.2.0.jre8
我们尝试调用 PreparedStatement.setArray() 方法来设置这个参数pstmt.setArray(1, conn.createArrayOf("int", new Integer[]{1,2,3}));
这里会受到两个阻碍,首先
SQL Server 的 PreparedStatement 的实现类 SQLServerPreparedStatement 的 setArray() 未实现,反编译出它的 setArray() 方法是 Read More
每种数据都有自己独特的自增列的声明方式,如 Oracle 的 Sequence, SQL Server 的 Identity, MySQL 的 auto_increment, PostgreSQL 的 Sequence 或 Serial。和 PostgreSQL 类似,DB2 也提供两种自增列的声明方式,它们是 Sequence 和 Identity。而本文主要着墨于 DB2 的 Identity 字段,并讲述它与 Sequence 的某种联系,以及它对数据表的导入的影响。DB2 的 Sequence
在 DB2 中声明一个 Sequence 与表的 Identity 字段的参数差不多,我们可以看作 Identity 是一个内联的 Sequence。先来看如何创建一个序列 Read More- 使用 Python 就难免要应对到不同数据库连接的问题,Python 目前也没有 Java 使用 JDBC 瘦客户端驱动那么方便。本人在用 Python 连接 SQL Server 时经常还是会有些问题,此文只着力于如何用 Python 连接 DB2 和 Oracle 数据库。
从本文中我们将会学到- Python 围绕着 ibm_db 来操作 DB2
- 以 Python DB-API 2.0 规范来操作 DB2
- cx_Oracle Python 库 + Oracle Instant Client 操作 Oracle
- 用 Oracle 的 SID 还是 Service Name 来连接数据库
- Python 中借助 JayDeBeApi 使用 JDBC 驱动来操作数据库(以 Oracle 为例)
- 从 JayDeBeApi 中我们了解到 JPype 有助于我们在 Python 中调用 Java
Python 操作 DB2
连接 DB2 数据库要简单的多,只要安装 ibm-db 库 Read More - 在使用 DB2 的 Community 版本的 Docker 镜像
ibmcom/db2进行测试,启动 Docker 容器的命令是$ docker run -name db2server --privileged=true -p 50000:50000 \
当使用多线程以及 JDBC 的 Batch Update 时,出现 "The transaction log for the database is full" 问题,一旦出现这个问题时,用数据库客户端连接后即使执行一条简单的 insert/update 语句也会报同样的错误。于是只能减少线程数和 Batch Update 时的记录来勉强过关,但性能上与其他数据库就有很大的差别了。 Read More
-e LICENSE=accept \
-e DB2INSTANCE=db2user \
-e DB2INST1_PASSWORD=password123 \
-e DBNAME=test \
ibmcom/db2 - 现在流行数据都有 Schema 的概念,一般作为数据库对象(表,函数,存储过程等)的命名空间。所以在数据库端往往存在 实例/数据库/Schema 这样层级划分。对于 DB2 和 Oracle 用客户端创建一个新的数据库并非易事,灵活的在数据库中较轻量的划分隔离空间的办法因数据库类型而异
- MySQL: 创建数据库(create database), create schema 是 create database 的别名
- PostgreSQL: create database 创建新的数据库,或在当前数据库下用 create schema 创建 schema
- SQLServer: 和 PostgreSQL 一样的自由,create database 创建新的数据库,或在当前数据库下用 create schema 创建 schema
- DB2: 用 create schema 创建新的 schema, 或创建数据库对象时直接加上前缀,create table abc.test1..., 没有 abc schema 则会自动创建
- Oracle: create schema 较麻烦,涉及到 authorization. 但可以通过 create user 创建新用户后就有了对应的新 schema
下面我们来了解下在 PostgreSQL/SQLServer 中创建新的 schema,如何在 JDBC 连接字串中指定默认 schema, 同时也涉及到 database/schema/user 的创建以及在 SQL 中如何切换。 Read More