记一次关于JDBC-Oracle配置的坑

1 什么是JDBC

  • JDBC(Java DataBase Connectivity,java 数据库连接),是JavaEE 平台下的一个技术规范
  • 它定义了Java 访问数据库的API、执行SQL 语句的标准
  • 可以为多种关系数据库提供统一访问

2. 关于数据库驱动

  • 数据库驱动是数据库厂商对JDBC 规范的具体实现的封装
  • 不同数据库产品的驱动名称、URL协议写法均有差异
  • 在程序中对数据库的操作都必须依赖数据库驱动来完成

3. JDBC的配置

JDBC编程过程中,必不可少的配置就是配置JDBC访问数据库的4大关键配置:Driver、URL、username和password。但是,由于市场上有很多中数据库厂商的数据库产品,各个厂商的数据库驱动又存在着差异,所以在配置过程中需格外注意找准数据库的驱动程序,尤其是url的写法。
我在完成一个项目的过程中,由于数据库使用的是Oracle,在本地和测试环境上运行良好,但是在正式环境中,项目一启动总是报错:“ORA-01017: invalid username/password; logon denied”,检查是否用户名、密码等配置出错了,经过多次检查都没配置错;为了排除有空格等其他不可见字符,使用其他的Oracle客户端用同样的用户名密码登录,结果成功,原因何在?!
着实让人抓狂,无奈翻开了《Java核心技术(卷二)》-5.3.1,赫然写着“在连接数据库时,我们必须使用各种与数据库类型相关的参数,例如主机名、端口号和数据库名”。难道URL配置出错了???那还得取问问各个数据库厂商?!经过查阅,Oracle数据库配置有SID和Service Name和TNSName几种种方式的配置,从9i之后由于并行计算和并发等性能的提高,推荐使用Service Name的方式提供服务。
下面着重记录下市场上常见的数据库URL写法:

Oracle

Oracle数据库的URL写法(用thin模式):
格式一:jdbc:oracle:thin:@//<host>:<port>/<service_name>
格式二:jdbc:oracle:thin:@<host>:<port>:<SID>
格式三:jdbc:oracle:thin:@<TNSName>
造成前文中我出现的问题,用格式一配置了SID方式访问数据库,哎,C!

MySQL

格式:jdbc:mysql://<host>:<port>/<db_name>

MariaDB

格式:jdbc:maria://<host>:<port>/<db_name>

MS SQL Server

  • 使用驱动msbase.jar、mssqlserver.jar、msutil.jar:
    格式一:jdbc:microsoft:sqlserver://<host>:<port>;DatabaseName=<db_name>
  • 使用驱动jtds-1.2.jar:
    格式二:jdbc:jtds:sqlserver://<host>:<port>/<db_name>;s=8.0;lastupdatecount=true

Sysbase

格式一:jdbc:Sysbase://<host>:<port>/<db_name>
格式二:jdbc:sybase:Tds:<host>:<port>/<db_name>

PostgreSQL

格式:jdbc:postgresql://<host>:<port>/<db_name>

DB2

格式:jdbc:db2://<host>:<port>/<db_name>

Informix

格式:jdbc:Informix-sqli://<host>:<port>/<db_name>:INFORMIXSER=myserver

附:JDBC-ODBC

Driver:sun.jdbc.odbc.JdbcOdbcDriver
url:jdbc:odbc:<dbSourceName>

4.JDBC编程步骤(MySQL为例)

public static final String URL = "jdbc:mysql://localhost:3306/test";
public static final String USER = "mysql";
public static final String PASS = "123456";

public static void main(String[] args) throws Exception {
	// 1.加载驱动程序
	Class.forName("com.mysql.jdbc.Driver");
	// 2. 获得数据库连接
	Connection conn = DriverManager.getConnection(URL, USER, PASS);
	// 3.操作数据库,实现增删改查
	Statement stmt = conn.createStatement();
	ResultSet rs = stmt.executeQuery("SELECT user_name, age FROM t_users");
	// 4.遍历结果集
	// 如果有数据,rs.next()返回true
	while (rs.next()) {
	     System.out.println(rs.getString("user_name") + " 年龄:" + rs.getInt("age"));
	}
}
<think>我们正在处理一个关于在MyBatis中使用XML配置实现MySQL批量更新的问题。 根据引用[1],我们知道在MySQL JDBC URL中设置`rewriteBatchedStatements=true`和`allowMultiQueries=true`参数有助于批量操作。 引用[2]和[3]展示了Oracle和MySQL中不同的批量更新写法。特别注意,MySQL不支持像Oracle那样的PL/SQL块(begin...end;),所以我们需要调整写法。 在MyBatis中,MySQL批量更新通常有两种方式: 1. 使用`<foreach>`标签拼接多个更新语句,并通过分号分隔,然后配合JDBC参数`allowMultiQueries=true`来允许一次执行多条SQL。 2. 使用`case when`语句构建一个更新多个录的单个SQL语句。 但是,请注意,引用[3]中展示了一个嵌套foreach的批量更新,但这种方式在MySQL中需要开启多语句支持。 我们将展示两种方式: 方式一:使用foreach循环生成多个update语句(需要开启allowMultiQueries) 方式二:使用case when(适合单字段更新,多字段更新会复杂) 由于用户要求批量修改数据,我们假设需要根据不同的条件更新多个录。 示例场景:根据id更新不同录的name和email字段。 方式一(推荐,且简单): 在MyBatis的mapper.xml中,我们可以这样写: ```xml <update id="batchUpdate" parameterType="java.util.List"> <foreach collection="list" item="item" index="index" separator=";"> UPDATE user_table SET name = #{item.name}, email = #{item.email} WHERE id = #{item.id} </foreach> </update> ``` 同时,确保JDBC URL中设置了`allowMultiQueries=true`,否则执行多条语句会报错。 方式二:使用case when(适用于更新多个字段,但SQL较长) ```xml <update id="batchUpdate" parameterType="java.util.List"> UPDATE user_table SET name = CASE id <foreach collection="list" item="item"> WHEN #{item.id} THEN #{item.name} </foreach> END, email = CASE id <foreach collection="list" item="item"> WHEN #{item.id} THEN #{item.email} </foreach> END WHERE id IN <foreach collection="list" item="item" open="(" separator="," close=")"> #{item.id} </foreach> </update> ``` 但是,方式二在更新多个字段时,每个字段都需要一个CASE语句,且当录数很大时,SQL语句会很长。 注意:在方式二中,如果某个id在列表中出现多次,则最后一个出现的会生效(因为SQL中WHEN的顺序就是foreach的顺序)。另外,如果列表中有重复id,建议去重。 根据引用[1],我们还需要在JDBC URL中设置`rewriteBatchedStatements=true`来优化批量更新性能(对于方式一,开启这个参数可以将多个语句打包发送,提高效率)。但是,方式二是一个单独的SQL,不需要这个参数。 因此,推荐使用方式一,因为它简单直观,且通过开启多语句支持,可以一次执行多个更新。但是要注意SQL注入风险,确保传入的id等参数是安全的。 另外,引用[3]中提到一个嵌套foreach的批量更新,它更新了不同语言环境下的多个字段。我们可以参考其思路,但注意它也是使用分号分隔多个更新语句,所以同样需要开启多语句支持。 总结:在MySQL中,使用MyBatis进行批量更新,可以采用分号分隔多个update语句的方式,并设置JDBC参数`allowMultiQueries=true`。 注意:在配置文件中,我们使用`&`来转义`&`,所以URL中应该是`&allowMultiQueries=true`。 最后,我们给出一个完整的配置示例: 在application.properties(或类似配置文件)中: ``` spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true ``` 在mapper.xml中,使用方式一的写法。 但是,如果用户不想开启多语句支持(因为多语句可能带来安全风险),那么可以采用方式二,但要注意方式二的局限性(如SQL长度限制,以及更新逻辑的复杂性)。 因此,请根据实际需求选择。 相关问题: 1. 在MyBatis中,如何配置MySQL的JDBC URL以支持批量更新? 2. 除了使用多个update语句,还有哪些方法可以实现MyBatis批量更新MySQL数据? 3. 使用多个update语句进行批量更新时,需要注意哪些安全问题?</think>在Java中使用MyBatis的XML配置实现MySQL批量更新,主要有两种常用写法。以下是详细配置和说明: ### 方法1:使用`<foreach>`拼接多个UPDATE语句(需开启多语句支持) ```xml <update id="batchUpdate" parameterType="java.util.List"> <foreach collection="list" item="item" separator=";"> UPDATE your_table SET column1 = #{item.value1}, column2 = #{item.value2} WHERE id = #{item.id} </foreach> </update> ``` **关键配置**: 1. JDBC URL需添加参数: ```ini jdbc:mysql://host:port/db?allowMultiQueries=true&rewriteBatchedStatements=true ``` - `allowMultiQueries=true`:允许分号分隔的多语句执行 - `rewriteBatchedStatements=true`:优化批量性能[^1] 2. Java调用: ```java List<YourEntity> dataList = ...; // 待更新数据集合 sqlSession.update("batchUpdate", dataList); ``` ### 方法2:使用CASE-WHEN动态生成单语句(无需多语句支持) ```xml <update id="batchUpdate" parameterType="java.util.List"> UPDATE your_table SET column1 = CASE id <foreach collection="list" item="item"> WHEN #{item.id} THEN #{item.value1} </foreach> END, column2 = CASE id <foreach collection="list" item="item"> WHEN #{item.id} THEN #{item.value2} </foreach> END WHERE id IN ( <foreach collection="list" item="item" separator=","> #{item.id} </foreach> ) </update> ``` ### 避指南 1. **SQL注入风险**: - 禁止在`${}`中拼接用户输入,必须使用`#{}`参数化[^3] - 示例错误写法:`WHERE id = ${item.id}` ❌ 2. **事务控制**: ```java try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { YourMapper mapper = session.getMapper(YourMapper.class); for (YourEntity item : dataList) { mapper.updateItem(item); // 单条更新操作 } session.commit(); // 统一提交 } ``` 3. **性能优化**: - 单批次数据量建议500-1000条 - 超大批量时需分页处理 ### 配置验证 检查JDBC连接参数: ```java System.out.println(conn.getClientInfo()); // 输出rewriteBatchedStatements等实际生效值 ``` > 两种方法各有优劣:方法1代码简洁但需多语句权限;方法2兼容性更好但SQL较长。根据实际数据库权限选择即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值