JAVA基础编程——数据库编程

在当前大数据时代,数据的流量已经越来越大,有时单单依靠内存来进行数据的处理已经不能满足需求了。因此在开发中,会不可避免地使用到数据库技术,JAVA自然也会支持对数据库操作的支持。

JDBC

JDBC(JAVA Database Connective,JAVA数据库连接技术)是由JAVA提供的一组与平台无关的数据库的操作标准,其本身由一组类和接口组成,并且在操作中将按照严格的顺序执行。

这样的表述表明JAVA的这种技术与平台无关,同时该技术规定了4中数据库操作的形式:

  • JDBC-ODBC桥接技术:Windows中的开放数据库连接(Open Database Connectivity, ODBC)是微软提供的数据库编程接口。而JDBC-ODBC桥接技术则是先利用ODBC技术作为数据库的连接方式,然后利用JDBC进行ODBC的连接,以实现数据库操作。该方法使用性能较差,但不需要进行第三方开发包配置,使用较为方便。
  • JDBC本地驱动:JDBC本地驱动是由不同的数据库厂商根据JDBC定义的操作标准实现各自的驱动程序,程序可以直接通过JDBC进行数据库的连接操作。该方法操作性好,但需要针对不同的数据库配置匹配对应的驱动程序。
  • JDBC网络驱动:JDBC网络驱动将利用特定的数据库连接协议进行数据库的网络连接。此方法可以连接任一服务器的数据库,使用灵活,开发方便。
  • JDBC协议驱动:JDBC协议驱动是利用JDBC提供的协议标准,将数据库的操作以特定的网络协议方式进行处理。

连接MySQL数据库

JAVA中数据库的相关操作在java.sql包中,该包中主要包含以下核心类和接口:

  • java.sql.DriverManager类:提供数据库的驱动管理,主要负责获取数据库的连接对象
  • java.sql.Connection接口:用于描述数据库的连接,可以用该接口关闭连接
  • java.sql.Statement接口:数据库的操作接口,通过连接对象打开
  • java.sql.PreparedStatement接口:数据库预处理操作接口,通过连接对象打开
  • java.sql.ResultSet接口:数据查询结果描述,通过该接口获取查询结果

整体看来,JDBC的操作步骤主要分为四个步骤:

加载数据库驱动程序

所有的JDBC都是由各个不同的数据库厂商提供的数据库驱动程序,这些驱动程序都是以jar包的形式给出。而连接MySQL数据库首先要保证本地存在对应的jar包,要提前在官网下载,并将其路径配置到CLASSPATH变量中。

本文使用的MySQL版本为8.0.20。

通过DriverManager类建立连接

操作数据库首先要建立连接,连接需要:

  • 连接地址
  • 用户名
  • 密码

然后使用DriverManager类进行连接:

static Connection getConnection(String url, String user, String password) // Attempts to establish a connection to the given database URL.

从上面定义看出,数据库连接使用Connection接口对象进行封装,因此只要有一个新Connection对象就表示要连接一次数据库。

利用Statement、PreparedStatement、ResultSet接口实现CRUD操作

Statement createStatement() // Creates a Statement object for sending SQL statements to the database.
PreparedStatement prepareStatement(String sql) // Creates a PreparedStatement object for sending parameterized SQL statements to the database.

释放资源

跟IO操作类似,数据库操作后最好显式释放资源。

import java.sql.*;

public class Demo {
	private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
	private static final String DBURL = "jdbc:mysql://localhost:3306/myemployees?useSSL=false&serverTimezone=UTC";
	private static final String USER = "root";
	private static final String PASSWORD = "********";
	
	public static void main(String[] args) throws Exception {
        Class.forName(DBDRIVER);
		Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
		System.out.println(conn);

        // CRUD
		
		conn.close();
	}
}

执行结果为:

com.mysql.cj.jdbc.ConnectionImpl@2f943d71

上面的代码先利用反射机制进行驱动程序的加载,然后建立了数据库连接,并进行了关闭,并没有实际的CRUD操作。

Statement

Statement接口主要用来进行数据库的CRUD操作,主要方法有:

ResultSet executeQuery(String sql) // Executes the given SQL statement, which returns a single ResultSet object.
int executeUpdate(String sql) // Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement.

这里看段代码:

import java.sql.*;

public class Demo {
	private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
	private static final String DBURL = "jdbc:mysql://localhost:3306/myemployees?useSSL=false&serverTimezone=UTC";
	private static final String USER = "root";
	private static final String PASSWORD = "********";
	
	public static void main(String[] args) throws Exception {
		Class.forName(DBDRIVER);
		Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
		
		Statement st = conn.createStatement();
		
		String sql = "select * from departments";
		ResultSet res = st.executeQuery(sql);
		while(res.next()) {
		    int depID = res.getInt("department_id");
			String depName = res.getString("department_name");
			int magID = res.getInt("manager_id");
			int locID = res.getInt("location_id");
			
			System.out.println("DepID is:" + depID + ",depName is:" + depName + ",magID is:" + magID + ",locID is:" + locID);
		}
		
		sql = "UPDATE departments SET manager_id = 201 WHERE department_id = 10";
		int len = st.executeUpdate(sql);
		
		st.close();		
		conn.close();
	}
}

数据的增删改其实逻辑都一样,只要sql语句写的没问题就OK。但是数据查询的结果是由ResultSet来接收的,而ResultSet的设计是按照数据类型的方式来保存返回数据的,这就要求需要针对数据库中每一列的属性进行分别获取。

上面的代码便是利用next判断是否截止,然后按照列属性逐个获取属性值,然后打印。

同时上边的代码只是为了说明一下使用方法,写sql语句并不是目的,在实际的开发中:

  • 要避免select *查询,会占用过大的内存
  • 要按照数据库的列顺序逐列获取属性值
  • 每列数据只能按照顺序取一次

上面的代码还可以修改为:

while(res.next()) {
    int depID = res.getInt(1);
	String depName = res.getString(2);
	int magID = res.getInt(3);
	int locID = res.getInt(4);
	
	System.out.println("DepID is:" + depID + ",depName is:" + depName + ",magID is:" + magID + ",locID is:" + locID);
}

这样的写法可以用于select name1,name2...这样的查询语句中,毕竟如果查询和属性值获取都要写重复的字符串有点多余,这样的写法可以按照列顺序进行逐个获取。

PreparedStatement

虽然StateMent能够用于CRUD,但是在进行insert操作时,需要进行字符串拼接操作,这个过程会很容易出错。

而PreparedStatement可以使用占位符sql语句来进行动态设置,这意味着字符串拼接的工作会被省略。

public interface PreparedStatement extends Statement

PreparedStatement prepareStatement(String sql) // Creates a PreparedStatement object for sending parameterized SQL statements to the database.

看下具体使用:

import java.sql.*;

public class Demo {
	private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
	private static final String DBURL = "jdbc:mysql://localhost:3306/myemployees?useSSL=false&serverTimezone=UTC";
	private static final String USER = "root";
	private static final String PASSWORD = "********";
	
	public static void main(String[] args) throws Exception {
		Class.forName(DBDRIVER);
		Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
		
		Statement st = conn.createStatement();
		
		String sql = "select * from departments";
		ResultSet res = st.executeQuery(sql);
		while(res.next()) {
		    int depID = res.getInt(1);
			String depName = res.getString(2);
			int magID = res.getInt(3);
			int locID = res.getInt(4);
			
			System.out.println("DepID is:" + depID + ",depName is:" + depName + ",magID is:" + magID + ",locID is:" + locID);
		}
		
		sql = "INSERT INTO departments(department_id, department_name, manager_id) VALUES (?,?,?)";
		PreparedStatement pst = conn.prepareStatement(sql);
		pst.setInt(1,12);
		pst.setString(2,"Tom");
		pst.setInt(3,102);
		
		int len = pst.executeUpdate();
		
		st.close();
		pst.close();
		conn.close();
	}
}

上面的代码就省略了字符串拼接,而是用?作为占位符,并在后续中赋值,执行sql语句,这样的代码就会整洁一点。

另外也不止查询才可以使用PreparedStatement,其它sql语句也可以使用该接口借助占位符实现sql语句。本文也不是主要介绍sql语句的,只是搞清楚JAVA中数据库操作的逻辑接口,复杂的sql就不赘述了。

批处理与事务

批处理

批处理是指一次性向数据库发出多条操作指令,然后一块执行。

在Statement和PreparedStatement接口中有关于批处理的操作:

// Statement
void addBatch(String sql) // Adds the given SQL command to the current list of commands for this Statement object.
int[] executeBatch() // Submits a batch of commands to the database for execution and if all commands execute successfully, returns an array of update counts.

// PreparedStateMent
void addBatch() // Adds a set of parameters to this PreparedStatement object's batch of commands.

下面的代码就实现了批处理:

import java.sql.*;
import java.util.Arrays;

public class Demo {
	private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
	private static final String DBURL = "jdbc:mysql://localhost:3306/myemployees?useSSL=false&serverTimezone=UTC";
	private static final String USER = "root";
	private static final String PASSWORD = "********";
	
	public static void main(String[] args) throws Exception {
		Class.forName(DBDRIVER);
		Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
		
		Statement st = conn.createStatement();
		
		st.addBatch("INSERT INTO departments(department_id, department_name, manager_id) VALUES (1001,12,13)");
		st.addBatch("INSERT INTO departments(department_id, department_name, manager_id) VALUES (1002,12,14)");
		st.addBatch("INSERT INTO departments(department_id, department_name, manager_id) VALUES (1003,12,15)");
		
		int res[] = st.executeBatch();
		System.out.println(Arrays.toString(res));
		
		st.close();
		conn.close();
	}
}

事务

事务保证了数据操作的完整性。

JDBC支持事务处理操作,相关方法定义在Connection接口中:

void commit() // Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by this Connection object.
void rollback() // Undoes all changes made in the current transaction and releases any database locks currently held by this Connection object.
void setAutoCommit(boolean autoCommit) // Sets this connection's auto-commit mode to the given state.

示例代码为:

import java.sql.*;
import java.util.Arrays;

public class Demo {
	private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
	private static final String DBURL = "jdbc:mysql://localhost:3306/myemployees?useSSL=false&serverTimezone=UTC";
	private static final String USER = "root";
	private static final String PASSWORD = "********";
	
	public static void main(String[] args) throws Exception {
		Class.forName(DBDRIVER);
		Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
		
		Statement st = conn.createStatement();
		conn.setAutoCommit(false);
		try {
		    st.addBatch("INSERT INTO departments(department_id, department_name, manager_id) VALUES (1004,12,13)");
			st.addBatch("INSERT INTO departments(department_id, department_name, manager_id) VALUES (1005,12,14)");
			st.addBatch("INSERT INTO departments(department_id, department_name, manager_id) VALUES (1006,12,15)");
		
			int res[] = st.executeBatch();
			System.out.println(Arrays.toString(res));
			
			conn.commit();
		} catch (Exception e) {
		    e.printStackTrace();
			conn.rollback();
		}
		
		st.close();
		conn.close();
	}
}

在手动进行事务处理时,首先要取消自动提交,然后在try中执行数据操作,并进行手动提交,而在catch中捕获错误,并进行回滚处理,以保证数据的完整性。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值