JDBC操作

JDBC编程

目前市面上数据库管理系统已经非常多,mysql,Oracle,SQLserver等等
在ODBC出现之前,对这些数据库的访问是一件非常麻烦的事情,因为这些数据库虽然都支持sql,但他们针对自己数据库的访问方法,所以当用户访问不同个的数据库时,就必须使用不同API来编写相应的数据库访问程序

  • ODBC(Open Database Connectivity)
    通过ODBC访问不同的数据库,无需对数据库访问程序进行修改,这样ODBC的应用越来越广泛
  • JDBC(java data base connectivity)
    按照ODBC的模式来制定的,它是一个通用的底层的支持sql功能的Java API

JDBC的组成

JDBC提供了两种接口

  1. JDBC API
    • 面向开发人员的API
  2. JDBC Driver API
    • 面向底层驱动程序开发商的API

JDBC API

JDBC API 是一系列的应用编程接口,可以用来进行数据库连接,访问数据等

JDBC API的主要编程接口:

  1. DriverManager
    • 驱动程序管理类
    • 用来装载驱动程序,并为创建数据库链接提供支持
  2. Connection
    • 是一个接口
    • 用来连接某一个指定的数据库
  3. Statement
    • 是一个接口
    • 提供了执行SQL语句,获取查询结果的方法
  4. PreparedStatement
    • 用于执行预编译的SQL语句
  5. ResultSet
    • 提供了对接口集进行处理的方法

JDBC Driver API

主要有四种类型

  1. JDBC-ODBC bridge
    • 通过将JDBC的调用全部委托给其他编程接口来实现
  2. 部分java技术的本地API驱动程序
    • 驱动程序部分实现通过JAVA语言
    • 其他的部分则委托给本地的数据库的客户段代码来实现
  3. 全部基于java技术的本地API程序
    • 这种驱动程序的实现全部通过Java语言
    • 通常由某个中间件服务器提供
    • 客户端程序可以使用数据库无关的协议和中间件服务器进行通信
    • 中间件服务器再讲客户端的调用转发给服务器进行处理
  4. 全部基于java技术的本地协议驱动程序
    • 全部基于java语言
    • 包含了特定数据库的访问协议,使得客户端可以直接同服务器进行通信

使用JDBC进行增删改

首先建表

  • 修改Mysql-WorkBench快捷键

    • 自动补全 ctrl+space
      • 但是和Ubuntu的输入法切换冲突
      • 修改/usr/share/mysql-workbench/data/main_menu.xml文件
      • modifier + Space 就是 Ctrl+space的意思,修改为不冲突的快捷键例如F2
      • 或者 直接 菜单栏 edit->auto complete 启动自动补全
  • 创建用户表

use jsp_db;
create table tbl_user(
    id int(11) unsigned not null auto_increment,
    name varchar(50) not null default '',
    password varchar(50) not null default '',
    email varchar(50) default '',
    primary key(id)
    )engine=InnoDB default charset=utf8;
  • 创建地址表
CREATE TABLE tbl_address (
    id INT(11) UNSIGNED not null auto_increment,
    city varchar(20) default null,
    country varchar(20) default null,
    user_id int(11) unsigned not null,
    primary key(id)
) engine=InnoDB default charset = utf8; 
  • 表中插入记录
insert into tbl_user(id,name,password,email)
values
(1, 'xiaoming', '123456','xiaoming@qq.com'),
(2, 'xiaozhang', '123456', 'xiaozhang@qq.com');

insert into tbl_address(city, country, user_id)
values
('beijing', 'china', 1),
('tianjin', 'china', 2);

查询初体验

  • JDBC执行流程

  • Eclise中

    • Alt+ ‘/’ 可以进行生成函数
  • 数据库查询

package com.JDBC.Test;

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

import com.mysql.jdbc.Driver;

public class JDBCTest {
	public static void main(String[] args) {
		String sql = "select * from tbl_user";
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		
		try {
			// 用于注册Mysql JDBC的驱动程序
			// forName 方法用于初始化参数指定的类,并创建一个对应的实例对象
			Class.forName("com.mysql.jdbc.Driver");
			// 这里url 指定了 数据库的 地址 端口 以及具体访问的库名
			String url = "jdbc:mysql://localhost:3306/jsp_db";
			String user = "root";
			String password = "root";
			// 获取Mysql 数据库的连接 这里使用的是 DriverManage 的 getConnection 方法
			connection = DriverManager.getConnection(url, user, password);
			// 创建一个Statement对象
			statement = connection.createStatement();
			// 使用Statement对象的executeQuery方法来发送Sql语句
			// executeQuery 方法返回一个 ResultSet对象
			resultSet = statement.executeQuery(sql);
			// 遍历ResultSet对象
			while (resultSet.next()) {
				System.out.println(resultSet.getInt("id"));
				System.out.println(resultSet.getString("name"));
				System.out.println(resultSet.getString("password"));
				System.out.println(resultSet.getString("email"));
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			try {
				// 关闭ResultSet对象的结果集
				resultSet.close();
			} catch (Exception e2) {
			}
			try {
				// 关闭Statement对象
				statement.close();
			} catch (Exception e2) {
			}
			try {
				// 关闭数据库连接
				connection.close();
			} catch (Exception e2) {
			}
		}
	}
}

增删改查

  • 首先写一个Connection的函数,这样执行就不用每次都写 那几条固定语句
public static Connection getConnection() {
		Connection conn = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			// 这里url 制定了 访问数据库的 地址 端口 以及 具体 库的名字
			String url = "jdbc:mysql://localhost:3306/jsp_db";
			String user = "root";
			String password = "root";
			// 获取Mysql 数据库的连接 这里使用的是 DriverManage 的 getConnection 方法
			conn = DriverManager.getConnection(url, user, password);
			
		} catch (Exception e) {
			// TODO: handle exception
		}
		return conn;
	}
  • 然后就是增删改的函数了
public static void insert() {
		Connection conn = getConnection();
		try {
			// 存储sql语句,用来向用户表中插入记录
			String sql = "insert into tbl_user(name,password,email)" 
						+ "values" 
						+"('Tom', '123456','Tom@qq.com'),('Anny', '123456', 'Anny@qq.com')";
			Statement st = conn.createStatement();
			// Statement中的executeUpdate方法,可以执行DML语句,包括insert update 以及 delete
			// 也可以执行没有返回结果的语句 例如:DDL语句 
			// 参数是一个字符串形式的sql语句,如果执行的是DML语句,那么返回影响的记录条数,如果是DDL语句则返回0
			// 会抛出sqlExcuption 以及 sqlTimeOut 的异常
			int count = st.executeUpdate(sql);
			System.out.println("向表中插入了" + count + "条语句");
			conn.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
public static void update() {
		Connection conn = getConnection();
		try {
			// 存储sql语句,用来向用户表中插入记录
			String sql = "update tbl_user set email='Tomm@163.com' where name = 'Tom'";
			Statement st = conn.createStatement();
			// Statement中的executeUpdate方法,可以执行DML语句,包括insert update 以及 delete
			// 也可以执行没有返回结果的语句 例如:DDL语句 
			// 参数是一个字符串形式的sql语句,如果执行的是DML语句,那么返回影响的记录条数,如果是DDL语句则返回0
			// 会抛出sqlExcuption 以及 sqlTimeOut 的异常
			int count = st.executeUpdate(sql);
			System.out.println("向表中更新了" + count + "条语句");
			conn.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
public static void delete_db() {
		Connection conn = getConnection();
		try {
			// 存储sql语句,用来向用户表中插入记录
			String sql = "delete from tbl_user where name='Tom'";
			Statement st = conn.createStatement();
			// Statement中的executeUpdate方法,可以执行DML语句,包括insert update 以及 delete
			// 也可以执行没有返回结果的语句 例如:DDL语句 
			// 参数是一个字符串形式的sql语句,如果执行的是DML语句,那么返回影响的记录条数,如果是DDL语句则返回0
			// 会抛出sqlExcuption 以及 sqlTimeOut 的异常
			int count = st.executeUpdate(sql);
			System.out.println("向表中删除了" + count + "条语句");
			conn.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
  • 之后只需要在 main 函数中 调用inset 等 方法就 能插入 修改 删除了

  • 需要注意的是,不要把sql语句写错

  • 执行之后,控制台会输出修改的语句的个数

  • main方法

public static void main(String[] args) {
		//insert();
		//update();
		delete_db();
	}

JDBC事务处理

数据库是一个多用户使用的共享资源
当多个用户使用数据库存取资源的时候,就会产生不同用户存取同一数据的情况
因此需要控制并发

  • 原子性

    • 事务中包含的操作都被看做是一个逻辑单元
    • 这个逻辑单元的操作 要么全部成功 要么全部失败
    • 事务中所有元素作为一个整体,提交或回滚
    • 事务的所有元素是不可分割的,是一个完整的操作
  • 一致性

    • 事务开始之前和事务结束以后,数据库都处于一致性状态
    • 数据库的完整性约束,没有被破坏
  • 隔离性

    • 对数据库进行修改的多个事务,是彼此隔离的
    • 事务必须是独立的,不应该以任何形式影响其他事务
  • 持久性

    • 事务完成之后,对于系统的影响是永久的
    • 该修改真实的修改了数据库,即使系统出现故障也会一直保留

事务语句

  • 开始事务
    • Begin transaction
  • 提交事务
    • Commit transaction
  • 回滚事务
    • Rollback transaction

举个例子:
我们有 user 和 address 表
在 address 表中 插入 Tom 的地址信息
在 user 表中 插入 id 为 1 的 Tom的个人信息

  • 不难发现,由于user表中原来就有id 为 1 的信息,所以user表插入失败
  • 但是,address 表却可以插入,因为没有主键冲突
  • 这就是 完整性 缺失

代码实例

public class TransAction {

	public static Connection getConnection() {
		Connection conn = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://localhost:3306/jsp_db";
			String user = "root";
			String password = "root";
			conn = DriverManager.getConnection(url, user, password);
			
		} catch (Exception e) {
		}
		return conn;
	}
	// 使用 throws SQLException 来捕获异常,因为如果数据插入失败的时候会抛出异常
	// 通过 这种方法 将异常传递给 上层函数 通过上层函数捕捉异常 进行回滚
	public static void insertUser(Connection conn) throws SQLException {
		String sql = "insert into tbl_user(name,password,email)" 
				+ "values" 
				+"('Tom', '123456','Tom@qq.com'),('Anny', '123456', 'Anny@qq.com')";
		Statement st = conn.createStatement();
		int count = st.executeUpdate(sql);
		System.out.println("向表中插入了" + count + "条语句");
	}
	
	public static void insertAddress(Connection conn) throws SQLException {
		String sql = "insert into tbl_address(id,city,country)" 
				+ "values" 
				+"(1, 'beijing','china'),(2, 'tianjing', 'china')";
		Statement st = conn.createStatement();
		int count = st.executeUpdate(sql);
		System.out.println("向表中插入了" + count + "条语句");
	}
	
	public static void main(String[] args) {
		Connection conn = null;
		try {
			conn = getConnection();
			//关闭自动提交
			conn.setAutoCommit(false);
			insertAddress(conn);
			insertUser(conn);
			
			conn.commit();
		} catch (SQLException e) {
			System.out.println("=====偶哟,捕获到SQL异常了呢====");
			e.printStackTrace();
			try {
				// 如果捕获到异常 那么说明数据插入失败,则要回滚到插入之前的状态
				// 避免出现,部分插入,部分没插入 所导致的 完整性缺失问题
				System.out.println("====现在开始数据回滚呢,请等会哦====");
				conn.rollback();
				System.out.println("====回滚成功呢,请再看看是哪里的代码有问题呢====");
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		} finally {
			try {
				// 如果 conn 连接 不为空的时候,最后要关闭连接
				if (conn != null) {
					conn.close();
				}
			} catch (Exception e3) {
				e3.printStackTrace();
			}
		}
	}

}

JDBC 优化

前面的写法都是直接将 数据库链接,用户名,密码等直接内嵌到代码中
但是这样的写法其实重用性特别差,一旦修改了密码那么所有的文件都需要修改

这个时候最好的方法就是写一个 配置文件,然后所有的数据链接都用这个配置文件
这里 默认 配置文件的后缀是 .properties

driver=com.mysql.jdbc.Driver
dburl=jdbc\:mysql\://localhost\:3306/jsp_db
user=root
password=root

直接写上面的内容就行了 不需要上面花里胡哨的

package com.JDBC.Test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

import com.mysql.jdbc.Driver;



public class DataConnectFactory {
	private static String driver;
	private static String dburl;
	private static String user;
	private static String password;
	private static final DataConnectFactory factory = new DataConnectFactory();
	private Connection connection;
	static {
		Properties prop = new Properties();
		try {
			InputStream in = DataConnectFactory.class.getResourceAsStream("dbconfig.properties");
			prop.load(in);
		} catch (Exception e) {
			System.out.println("==配置问价出错了呢==");
		}
		
		driver = prop.getProperty(driver);
		dburl = prop.getProperty(dburl);
		password = prop.getProperty(password);
		user = prop.getProperty(user); 
	}
	//定义默认构造函数
	private DataConnectFactory(){
		
	}
	// 单例模式
	public static DataConnectFactory getInstance() {
		return factory;
	}
	
	public Connection makeConnection() {
		try {
			Class.forName(driver);
			connection = DriverManager.getConnection(dburl, user, password);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return connection;
	}
}


这里使用了静态代码块

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值