JDBC学习

本文深入讲解了JDBC的基本操作,包括简单数据查询、数据添加、批量数据添加、事务控制、存储过程调用及元数据获取等核心内容。通过对比Statement与PreparedStatement的性能,强调了PreparedStatement在SQL注入防护和代码可读性上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Jdbc

1 简单数据查询

@Test

public void select() throws Exception {

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

try {

Class.forName("com.mysql.jdbc.Driver");

conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");

stmt = conn.createStatement();

rs = stmt.executeQuery("select * from student_table");

while (rs.next()) {

System.out.println(rs.getInt(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));

}

} finally {

if (rs != null) {

rs.close();

}

if (stmt != null) {

stmt.close();

}

if (conn != null) {

conn.close();

}

}

}

2 数据添加

使用PreparedStatement的好处:

1  PreparedStatement可以使用占位符,是预编译的. 批处理比Statement效率高,最大程度的提高性能。

JDBC驱动会发送一个网络请求到数据解析和优化这个查询. 而执行时会产生另一个网络请求. 在JDBC驱动中,减少网络通讯是最终的目的. 如果我的程序在运行期间只需要一次请求, 那么就使用Statement. 对于Statement, 同一个查询只会产生一次网络到数据库的通讯.当使用PreparedStatement池时, 如果一个查询很特殊, 并且不太会再次执行到, 那么可以使用Statement. 如果一个查询很少会被执行,但连接池中的Statement池可能被再次执行, 那么请使用PreparedStatement. 在不是Statement池的同样情况下, 请使用Statement.

2 提高代码的可读性和可维护性;

3 可以防止SQL注入

SQL注入指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。

 

Statement:

@Test

public void insertUseStatement() throws Exception {

long start = System.currentTimeMillis();

Connection conn = null;

Statement stmt = null;

try {

Class.forName("com.mysql.jdbc.Driver");

conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");

stmt = conn.createStatement();

for (int i = 0; i < 1000; i++) {

stmt.executeUpdate("insert into student_table values(null,'姓名" + i + "',1)");

}

System.out.println("使用Statement费时:" + (System.currentTimeMillis() - start));

} finally {

if (stmt != null) {

stmt.close();

}

if (conn != null) {

conn.close();

}

}

}

 

插入1000条数据的耗时:

使用Statement费时:67123

 

PreparedStatement:

@Test

public void insertUsePrepare() throws Exception {

long start = System.currentTimeMillis();

Connection conn = null;

PreparedStatement pstmt = null;

try {

Class.forName("com.mysql.jdbc.Driver");

conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");

pstmt = conn.prepareStatement("insert into student_table values(null,?,1)");

for (int i = 0; i < 1000; i++) {

pstmt.setString(1, "姓名" + i);

pstmt.executeUpdate();

}

System.out.println("使用PreparedStatement费时:" + (System.currentTimeMillis() - start));

} finally {

if (pstmt != null) {

pstmt.close();

}

if (conn != null) {

conn.close();

}

}



}

 

输出:

使用PreparedStatement费时:65633

 

3 批量数据添加

@Test

public void insertUseBatch() throws Exception {

long start = System.currentTimeMillis();

Connection conn = null;

Statement stmt = null;

try {

Class.forName("com.mysql.jdbc.Driver");

conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");

stmt = conn.createStatement();

for (int i = 0; i < 1000; i++) {

stmt.addBatch("insert into student_table values(null,'姓名" + i + "',1)");

if ((i + 1) % 300 == 0) {

stmt.executeBatch();

}

}

stmt.executeBatch();

System.out.println("使用Batch费时:" + (System.currentTimeMillis() - start));

} finally {

if (stmt != null) {

stmt.close();

}

if (conn != null) {

conn.close();

}

}

}

4 事务控制

@Test

public void insertInTransaction() throws Exception {

String[] sqls=new String[]{

"insert into student_table values(null,'aaa',1)",

"insert into student_table values(null,'bbb',1)",

"insert into student_table values(null,'ccc',1)",

"insert into student_table values(null,'ccc',1)"

};

Connection conn=null;

Statement stmt=null;

try {

Class.forName(driver);

conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");

conn.setAutoCommit(false);

stmt = conn.createStatement();

for (String sql : sqls) {

stmt.executeUpdate(sql);

}

conn.commit();

} finally {

if (stmt != null) {

stmt.close();

}

if (conn != null) {

conn.close();

}

}

}

5 存储过程调用

@Test
	public void callProcedure() throws Exception {
		Connection conn = null;
		CallableStatement cstmt = null;
		try {
			// 加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 获取数据库连接
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");
			// 使用Connection来创建一个CallableStatment对象
			cstmt = conn.prepareCall("{call add_pro(?,?,?)}");
			cstmt.setInt(1, 4);
			cstmt.setInt(2, 5);
			// 注册CallableStatement的第三个参数是int类型
			cstmt.registerOutParameter(3, Types.INTEGER);
			// 执行存储过程
			cstmt.execute();
			// 获取,并输出存储过程传出参数的值。
			System.out.println("执行结果是: " + cstmt.getInt(3));
		} finally {
			if (cstmt != null) {
				cstmt.close();
			}
			if (conn != null) {
				conn.close();
			}
		}
	}

6 元数据获取

public class DatabaseMetaDataTest {
	private String driver;
	private String url;
	private String user;
	private String pass;
	Connection conn;
	ResultSet rs;

	public void initParam(String paramFile) throws Exception {
		// 使用Properties类来加载属性文件
		Properties props = new Properties();
		props.load(new FileInputStream(paramFile));
		driver = props.getProperty("driver");
		url = props.getProperty("url");
		user = props.getProperty("user");
		pass = props.getProperty("pass");
	}

	public void info() throws Exception {
		try {
			// 加载驱动
			Class.forName(driver);
			// 获取数据库连接
			conn = DriverManager.getConnection(url, user, pass);
			// 获取的DatabaseMetaData对象
			DatabaseMetaData dbmd = conn.getMetaData();
			// 输出此数据库产品的名称和版本号
			System.out.println(dbmd.getDatabaseProductName()+" "
					+ dbmd.getDatabaseProductVersion());
			// 获取此 JDBC 驱动程序的名称
			System.out.println(dbmd.getDriverName()+dbmd.getDriverVersion());
			// 获取MySQL支持的所有表类型
			ResultSet rs = dbmd.getTableTypes();
			System.out.println("----MySQL支持的表类型信息------");
			printResultSet(rs);
			// 获取当前数据库的全部数据表 获取可在给定类别中使用的表的描述。
			// 仅返回与类别、模式、表名称和类型标准匹配的表描述。它们根据 TABLE_TYPE、TABLE_CAT、TABLE_SCHEM 和
			// TABLE_NAME 进行排序。
			/**
			 *  TABLE_CAT String => 表类别(可为 null) 
 				TABLE_SCHEM String => 表模式(可为 null) 
				TABLE_NAME String => 表名称 
				TABLE_TYPE String => 表类型。典型的类型是 "TABLE"、"VIEW"、"SYSTEM TABLE"、
				"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS" 和 "SYNONYM"。 
			 */
			rs = dbmd.getTables(null, null, "%", new String[] { "TABLE" });
			System.out.println("----当前数据库里的数据表信息-----");
			printResultSet(rs);
			// 获取student_table表的主键
			//表类别 表模式 表名称
			rs = dbmd.getPrimaryKeys(null, null, "student_table");
			System.out.println("----student_table表的主键信息-----");
			printResultSet(rs);
			// 获取当前数据库的全部存储过程 类别名称 模式名称的模式 过程名称模式
			rs = dbmd.getProcedures(null, null, "%");
			System.out.println("----当前数据库里的存储过程信息-----");
			printResultSet(rs);
			// 获取teacher_table表和student_table之间的外键约束
			//父键表类别 模式 导出该键表的名称 类别 模式名称 导入该键标的名称
			rs = dbmd.getCrossReference(null, null, "teacher_table", null,
					null, "student_table");
			System.out.println("----teacher_table表和student_table之间的外键约束-----");
			printResultSet(rs);
			// 获取student_table表的全部数据列 表类别 表模式 表明称 列名称
			rs = dbmd.getColumns(null, null, "student_table", "%");
			System.out.println("----student_table表的全部数据列-----");
			printResultSet(rs);
		}
		// 使用finally块来关闭数据库资源
		finally {
			if (rs != null) {
				rs.close();
			}
			if (conn != null) {
				conn.close();
			}
		}
	}

	public void printResultSet(ResultSet rs) throws SQLException {
		ResultSetMetaData rsmd = rs.getMetaData();
		// 打印ResultSet的所有列标题
		for (int i = 0; i < rsmd.getColumnCount(); i++) {
			System.out.print(rsmd.getColumnName(i + 1) + "\t");
		}
		System.out.print("\n");
		// 打印ResultSet里的全部数据
		while (rs.next()) {
			for (int i = 0; i < rsmd.getColumnCount(); i++) {
				System.out.print(rs.getString(i + 1) + "\t");
			}
			System.out.print("\n");
		}
		rs.close();
	}

	public static void main(String[] args) throws Exception {
		DatabaseMetaDataTest dt = new DatabaseMetaDataTest();
		dt.initParam("mysql.ini");
		dt.info();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流光影下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值