jdbc使用分析

Posted 九死九歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdbc使用分析相关的知识,希望对你有一定的参考价值。

  JDBC,全称Java Database Connectivity,就是说你操作数据库,要么自己手动写,要么用java的jdbc框架自动化操作数据库。

  另外java.sql包里面几乎全都是接口,没有实现类。实现类几乎都是各个数据库开发公司整的外部库。我们这里用的是mysql的jdbc外部库。

一、建立java与MySQL的连接

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * <p>测试与数据库建立连接</p>
 * @author 九死九歌
 */
public class Demo01 {

	public static void main(String[] args) {
		/*加载驱动类*/
		try {
			Class cls = Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");
		}

		try {

			/*建立连接*/
			/*建立连接的过程中内部包含了Socket对象,所以比较耗时!这是Connection对象管理的一个特点*/
			/*真正做开发时都会选择用连接池来连接对象*/
			Connection con = DriverManager.getConnection
					("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			System.out.println(con);

			con.close();

		} catch (SQLException e) {
			System.err.println("sql语句有问题");
			e.printStackTrace();
		}

	}

}

二、利用Statement执行MySQL语句

  实际上Statement PreparedStatement CallableStatement都可以执行MySQL语句,并且第一个是后两个的父类。较为常用的是第二种,第三种几乎不用,我这里也就只说前两种。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 测试用Statement执行sql语句以及sql注入问题
 * @author 孙培迪
 */
public class Demo02 {

	public static void main(String[] args) {

		/*加载驱动类*/
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");
		}

		try(Connection con = DriverManager.getConnection
				("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			Statement stmt = con.createStatement()) {

			/* Statement不常用,因为他执行语句要自己拼字符串 */
			/* 一旦字符串是拼起来的,那就容易发生SQL注入,被人家攻击你的库 */

			String name  = "宋浩";
			int pwd = 123456;
			String sql = "insert into t_user (username, pwd, regTime) values ('"
					+name+"', "+pwd+", now())";
			stmt.execute(sql);

			/* 所以实际开发的过程中使用的都是PreparedStatement,即预编译的Statement */

		} catch (SQLException e) {
			System.err.println("sql语句有问题");
			e.printStackTrace();
		}

	}

}

三、利用PreparedStatement执行MySQL语句

  这个比上面那个更常用。

import java.sql.*;

/**
 * <p>测试PreparedStatement</p>
 * @author 九死九歌
 */
public class Demo03 {

	public static void main(String[] args) {
	
		/*加载驱动类*/
		try {
			Class cls = Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");	
		}

		String sql = "insert into t_user (username, pwd, regTime) values (?, ?, ?)"; // ?叫做占位符
		try(Connection con = DriverManager.getConnection
				("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			PreparedStatement ps = con.prepareStatement(sql)) {

//			ps.setString(1, "汤家凤"); // 参数索引要从1开始
//			ps.setString(2, "123456");

			/* 也可以用setObject,完全不用管类型。 */
			ps.setObject(1, "汤家凤");
			ps.setObject(2, "123456");
			/* 这里可以setDate,当然也可以setObject */
//			ps.setDate(3, new Date(System.currentTimeMillis()));
			ps.setObject(3, new Date(System.currentTimeMillis()));
			ps.execute();

		} catch (SQLException e) {
			System.err.println("sql语句有问题");
			e.printStackTrace();
		}

	}

}

四、探究ResultSet结果集和PreparedStatement的executeQuery()

import java.sql.*;

/**
 * <p>测试ResultSet结果集的基本用法</p>
 * @author九死九歌
 */
public class Demo04 {
	/* con ps 和 rs 可以试着用try-with-resource */
	public static void main(String[] args) {

		/*加载驱动类*/
		try {
			Class cls = Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");
		}

		String sql = "select id, username, pwd from t_user where id>?"; // ?叫做占位符
		try(Connection con = DriverManager.getConnection
				("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			PreparedStatement ps = con.prepareStatement(sql)) {

			ps.setObject(1, 1);

			ResultSet rs = ps.executeQuery();
			while (rs.next()) {
				System.out.print(rs.getInt(1));
				System.out.print("|" + rs.getString(2));
				System.out.println("|" + rs.getString(3));
			}

		} catch (SQLException e) {
			System.err.println("sql语句有问题");
			e.printStackTrace();
		}


	}

}

五、Batch批处理

  对于大量的批处理,建议使用Statement,因为PreparedStatement的预编译空间有限,当数据量特别大时,会发生异常。

package com.spd.jdbc;

import java.sql.*;

/**
 * <p>测试批处理的基本方法</p><br/>
 * <p>对于大量的批处理,建议使用Statement,因为PreparedStatement的预编译空间有限,当数据量特别大时,会发生异常。(不要叫我复读机)<p/>
 * @author 九死九歌
 */
public class Demo05 {

	public static void main(String[] args) {
	
		/*加载驱动类*/
		try {
			Class cls = Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");
		}

		try(Connection con = DriverManager.getConnection
				("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			Statement stmt = con.createStatement();) {

			con.setAutoCommit(false); // 设置为事物手动提交(false)

			for (int i = 0; i < 1000; i++) {
				stmt.addBatch("insert into t_user(username, pwd, regTime) values ('僵尸粉"+(i+1)+"', '123456', now())");
			}

			stmt.executeBatch(); // 进行批处理
			con.commit(); // 提交事务


		}catch (SQLException e) {
			System.err.println("sql语句有问题");
			e.printStackTrace();
		}

	}

}

六、事务

1.概念:

   一组要么同时执行成功,要么同时执行失败的SQL语句。是数据库操作的一个执行单元!

2.事务开始于:

  • 连接到数据库上,并执行条DML语句(INSERT、 UPDATE或DELETE)。
  • 前一个事务结束后,又输入了另外一条DML语句。

3.事务结束于:

  • 执行COMMI或ROLL BACK语句。
  • 执行一条DDL语句 ,例如CREATE TABLE语句;在这种情况下,会自动执行COMMIT语句。
  • 执行一条DCL语句,例如GRANT语句;在这种情况下,会自动执行
    COMMIT语句。
  • 断开与数据库的连接。
  • 执行了一条DML语句,该语句却失败了;在这种情况中,会为这个无效的
    DML语句执行ROLLBACK语句。

4.事务的四大特点(ACID):

  • atomicity(原子性)
    • 表示一一个事务内的所有操作是一个整体,要么全部成功,要么全失败;
  • consistency(一致性)
    • 表示一一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前的状态。
  • isolation(隔离性)
    • 事务查看数据时数据所处的状态,要么是另一-并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
  • durability(持久性)
    • 持久性事务完成之后,它对于系统的影响是永久性的。

(隔离性相当于对数据库加上了一个sychronized属性)

5.事务隔离级别由高到低:

  1. 读取未提交(read uncommitted)
  2. 读取已提交(read committed)
  3. 可重复读(repeatable read)
  4. 序列化(serializable)

越往下隔离性越低效率越低,sychronized程度越高,一般用的都是第二种读取已提交。

import java.sql.*;

/**
 * <p>测试事务的基本概念和用法</p>
 * @author 九死九歌
 */
public class Demo06 {

	public static void main(String[] args) {

		/*加载驱动类*/
		try {
			Class cls = Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");
		}

		try(Connection con = DriverManager.getConnection
				("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			PreparedStatement ps1 = con.prepareStatement
				("insert into t_user (username, pwd) values (?, ?)");
			PreparedStatement ps2 = con.prepareStatement
					("insert into t_user (username, pwd) values (?, ?, ?)");) {

			con.setAutoCommit(false); // jdbc中默认事务自动提交(true),所以要手动改成false

			ps1.setObject(1, "二次元刀酱-刀哥");
			ps1.setObject(2, "louniuzhile");
			ps1.execute();
			System.out.println("网络世界真真假假,妹有人是不怕屎滴");

			try {
				Thread.sleep(5000);
			} catch (InterruptedException ignored){}

			ps2.setObject(1, "东北虎哥");
			ps2.setObject(2, "woshigesanbing");
			ps2.execute();
			System.out.println("我徒弟呢?我徒弟!那是我徒弟!杀马特团长我跟你没完~~~");

			/* 这俩要成功同时成功,要失败同时失败,所以即便ps1没问题,有问题的是ps2,仍然是两个都无法执行。 */

			con.commit();

		} catch (SQLException e) {
			System.err.println("SQL语法出现异常");
			e.printStackTrace();
		}

	}

}

七、jdbc的时间处理

  sql包用于事件处理的类有三个,这三个都继承自util包的Date

  • Date:表示年月日
  • Time:表示时分秒
  • TimeStamp:表示年月日时分秒

  1.利用System.currentTimeMillis()插入当前时间

import java.sql.*;

/**
 * <p>测试事件的处理(java.sql.Date Time TimeStamp)</p>
 * @author 九死九歌
 */
public class Demo07 {

	public static void main(String[] args) {

		/*加载驱动类*/
		try {
			Class cls = Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");
		}

		try(Connection con = DriverManager.getConnection
				("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			PreparedStatement ps = con.prepareStatement
				("insert into t_user (username, pwd, regTime, logTime) values (?, ?, ?, ?)");) {

			ps.setObject(1, "徒步阿龙");
			ps.setObject(2, "xingfuankang");

			/* 利用sql包的Date类(注意:这个可不是utils包的) */
			Date date = new Date(System.currentTimeMillis());
			ps.setDate(3, date);

			/* 同为sql包的TimeStamp类 */
			Timestamp stamp = new Timestamp(System.currentTimeMillis()); // 如果要插入指定日期,可以使用Calendar、DateFormat
			ps.setTimestamp(4, stamp);

			ps.execute();
			System.out.println("我害怕鬼,但是鬼未伤我分毫\\n我不害怕人,但是人把我害得 遍  体  鳞  伤");

		} catch (SQLException e) {
			System.err.println("SQL语法出现异常");
			e.printStackTrace();
		}

	}

}

  2.随机插入时间

import java.sql.*;

/**
 * <p>测试事件的处理(java.sql.Date Time TimeStamp)</p>
 * @author 九死九歌
 */
public class Demo07 {

	public static void main(String[] args) {

		/*加载驱动类*/
		try {
			Class cls = Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");
		}

		try(Connection con = DriverManager.getConnection
				("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			PreparedStatement ps = con.prepareStatement
				("insert into t_user (username, pwd, regTime, logTime) values (?, ?, ?, ?)");) {

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

				ps.setObject(1, "徒步阿龙" + i + "号");
				ps.setObject(2, "xingfuankang");

				long n = (long) Math.ceil(1000000000L * Math.random());
				n %= 1000000000L;
				n -= 1000000000L /2;

				/* 利用sql包的Date类(注意:这个可不是utils包的) */
				Date date = new Date(System.currentTimeMillis()-n);
				ps.setDate(3, date);

				/* 同为sql包的TimeStamp类 */
				Timestamp stamp = new Timestamp(System.currentTimeMillis()-n); // 如果要插入指定日期,可以使用Calendar、DateFormat
				ps.setTimestamp(4, stamp);

				ps.execute();

			}

			System.out.println("我害怕鬼,但是鬼未伤我分毫\\n我不害怕人,但是人把我害得 遍  体  鳞  伤");

		} catch (SQLException e) {
			System.err.println("SQL语法出现异常");
			e.printStackTrace();
		}

	}

}

  3.对时间段进行数据查询

import java.sql.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
 *
 * <p>测试事件的处理(java.sql.Date Time TimeStamp)</p><br/>
 * <i>取出指定时间段的</i><b>数据<b/>
 * @author 九死九歌
 */
public class Demo08 {

	/**
	 * <p>将字符串代表的时间转化成长整形</p>
	 * (格式为yyyy-mm-dd hh:mm:ss)
	 * @param str
	 * @return
	 */
	public static long stringToDate(String str) {
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		try {
			return format.parse(str).getTime();
		} catch (ParseException e) {
			return -1;
		}
	}

	public static void main(String[] args) {

		/*加载驱动类*/
		try {
			Class cls = Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.err.println("未找到驱动类!");
		}

		ResultSet rs = null;

		try(Connection con = DriverManager.getConnection
				("jdbc:mysql://localhost:3306/testjdbc", "root", "root");
			PreparedStatement ps = con.prepareStatement
				("select * from t_user where regTime>? and regTime<?");) {

			Date start = new Date(stringToDate("2021-6-20 00:00:00"));
			Date end   = new Date(stringToDate("2021-6-30 00:00:00"));

			ps.setDate(1, start);
			ps.setDate(2, end);
			rs 以上是关于jdbc使用分析的主要内容,如果未能解决你的问题,请参考以下文章

关于mysql驱动版本报错解决,Cause: com.mysql.jdbc.exceptions.jdbc4Unknown system variable ‘query_cache_size(代码片段

面试常用的代码片段

SpringBoot - 05. 数据访问之JDBC(源码分析+代码下载)

如何在片段中填充列表视图?

使用Java代码通过JDBC连接只启用Sentry的Impala异常分析

Android 插件化VirtualApp 源码分析 ( 目前的 API 现状 | 安装应用源码分析 | 安装按钮执行的操作 | 返回到 HomeActivity 执行的操作 )(代码片段