Java 数据库编程

Java和数据库连接的方法

·····Native API (不能跨平台)
·····ODBC/JDBC-ODBC (效率差,无法跨平台)
·····JDBC (主流) Java Database Connectivity

Java SQL操作类库

java.sql.* (接口类)
javax.sql* (接口类)
根据数据库版本和JDBC含本合理选择jar包

连接字符串

-jdbc:oracle:thin:@127.0.0.1(IP可修改):1521(端口可改):dbname(数据库名可改)
-jdbc:mysql://localhost(IP可修改):3306(端口可改)/mydb(数据库名可改)
-jdbc:sqlserver://localhost:1433:DatabaseName=dbname

Java连接数据库操作步骤

在这里插入图片描述

构建连接(搭桥)

  • 注册驱动,寻找材质(哪种数据库),class.forName("…");
  • 确定对岸目标,建桥Connection

执行操作(派个人过桥,提个篮子,去拿数据)

  • Statement (执行者)
  • ResultSet(结果集)

释放连接(拆桥) connection.close()
在这里插入图片描述

Statement 执行者类
  • 使用executeQuery()执行select语句,返回结果(二维数组)放在ResultSet
  • 使用executeUpdate()执行insert/update/delete,返回修改的行数
  • 一个Statement对象一次只能执行一个命令
ResultSet 结果对象
  • next()判断是否还有下一条记录
  • getInt/getString/getDouble/…获取单元格数据
  • 可以按索引位置,可以按照列名
例子

step 1 chu创建mysql数据库(在navicat中)
连接名为test 密码为12345
注意如果设置的密码与之前mysql密码不同会出现报错在这里插入图片描述
在这里插入图片描述
在DB连接下新建数据库test(注意后面连接要的是数据库名)
在这里插入图片描述
在数据库test中创建表t_book (int varchar double)
在这里插入图片描述

在这里插入图片描述
注意:使用java.sql包

查询数据库

package DataBase;

//注意都是java.sql.*下的
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;  

public class SelectTest {
		public static void main(String[] args) {
			// 构建数据库与Java之间的桥梁
			try {
//				完成类的加载 com.mysql.jdbc.Driver类来源于(pom文件)的jar包
				Class.forName("com.mysql.jdbc.Driver"); 
				System.out.println("注册驱动成功");
			} catch (ClassNotFoundException e) {
				System.out.println("注册驱动失败");
				e.printStackTrace();
				return ;
			} 
			
			// 定义连接字符串  test是数据库名 不是连接名也不是表名
			String url = "jdbc:mysql://localhost:3306/test";  
			Connection conn = null;
			try {
//				构建桥梁 url 用户名密码(mysql数据库的) 这里好像永远都是root
				conn = DriverManager.getConnection(url, "root", "12345");
				
//				创建数据库执行者
				Statement stmt = conn.createStatement();
				System.out.println("创建Statement成功!");
				
//				执行SQL语句并返回结果到ResultSet
				ResultSet rs = stmt.executeQuery("select tookid, bookname, price from t_book order by tookid");

//				开始遍历ResultSet数据
				while(rs.next()) {
					System.out.println(rs.getInt(1)+","+rs.getString(2)+","+rs.getDouble("price"));
				}
				
				rs.close();
				stmt.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				if(null != conn) {
					try {
						conn.close();
						System.out.println("成功关闭连接");
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}

}

增删改数据库


import java.sql.*;

public class UpdateTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		executeUpdate("update t_book set price = 300.0 where tookid = 101");
		executeUpdate("insert into t_book(tookid, bookname, price) values(104, '编译原理', 90)");
		executeUpdate("delete from t_book where tookid = 102");
	}
	
	public static void executeUpdate(String sql) {
		// 构建数据库与Java之间的桥梁
		try {
//			完成类的加载 com.mysql.jdbc.Driver类来源于(pom文件)的jar包
			Class.forName("com.mysql.jdbc.Driver"); 
			System.out.println("注册驱动成功");
		} catch (ClassNotFoundException e) {
			System.out.println("注册驱动失败");
			e.printStackTrace();
			return ;
		} 
		
		String url = "jdbc:mysql://localhost:3306/test";  
		Connection conn = null;
		try {
//			构建桥梁 url 用户名密码(mysql数据库的)
			conn = DriverManager.getConnection(url, "root", "12345");
			
//			创建数据库执行者
			Statement stmt = conn.createStatement();
			System.out.println("创建Statement成功!");
			
//			执行SQL语句
			int result = stmt.executeUpdate(sql);	
			
			stmt.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(null != conn) {
				try {
					conn.close();
					System.out.println("成功关闭连接");
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

在这里插入图片描述

JDBC高级操作

---------------------------------JDBC事务 -----------------------------------
事务:

数据库事务DataBase Transaction
作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行
事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性

JDBC事务
  • 关闭自动提交(jdbc默认自动提交),实现多语句同一事务
  • connection.setAutoCommit(false);
  • connection.commit(); 提交事务
  • connection.rollback(); 回滚事务 (上述语句全部废弃不执行)
  • 保存点机制
    ···connection.setSavepoint()
    ···connection.rollback(Savepoint)

例子
清空DataBase后运行

public class TransactionTest {
//	JDBC事务处理
	public static void main(String[] args) {
		try {
//			完成类的加载 com.mysql.jdbc.Driver类来源于(pom文件)的jar包
			Class.forName("com.mysql.jdbc.Driver"); 
			System.out.println("注册驱动成功");
		} catch (ClassNotFoundException e) {
			System.out.println("注册驱动失败");
			e.printStackTrace();
		} 

		// 定义连接字符串  test是数据库名 不是连接名也不是表名
		String url = "jdbc:mysql://localhost:3306/test";  
		Connection conn = null;
		try {
//		构建桥梁 url 用户名密码(mysql数据库的)
			conn = DriverManager.getConnection(url, "root", "12345");
			conn.setAutoCommit(false); // 关闭自动提交		

			insertBook(conn, "insert into t_book values(105, 'qqqq', 10)");
			insertBook(conn, "insert into t_book values(106, 'wwww', 10)");
			insertBook(conn, "insert into t_book values(107, 'eeee', 10)");
			Savepoint phase1 = conn.setSavepoint(); // 设置一个保存点
			insertBook(conn, "insert into t_book values(108, 'wwww', 10)");
			insertBook(conn, "insert into t_book values(109, 'eeee', 10)");
			conn.rollback(phase1); // 回滚到phase1保存点,即上面两行无效
			conn.commit(); // 注意一条语句如果被回滚就无法再tcommit故上述两行无效
			System.out.println("操作成功");
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				if(null != conn) {
					try {
						conn.close();
						System.out.println("成功关闭连接");
						} catch (SQLException e) {
								e.printStackTrace();
						}
				}
			}
	}
	public static void insertBook(Connection conn, String sql) {
		try {
//				构建数据库执行者
			Statement stmt = conn.createStatement();
			System.out.println("创建Statement成功!");
//				执行SQL语句
			int result = stmt.executeUpdate(sql);
			stmt.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
}

运行结果
在这里插入图片描述

------------------------PreparedStatement--------------------------
拼接字符串有风险

如恶意SQL语句(注入攻击)
在这里插入图片描述

PreparedStatement
  • Java提供PreparedStatement,更为安全执行SQL
  • 和Statement区别是使用“?”代替字符串拼接
  • 使用setXXX(int,Object)的函数来实现对于?的替换
    —注:不需要考虑字符串的两侧单引号
    —参数赋值,清晰明了,拒绝拼接错误
  • 提供addBatch批量更新功能
  • Select语句一样用ResultSet接受结果

如果有大量的sql语句,它们结构相同,仅仅差别在具体数值上,可以通过addBatch方法进行批量操作。这样会提高性能,减少数据库负担。
如下述例子中的patchInsertBook()函数,在这里插入图片描述
这样操作的效率要高于采用executeUpdate(要执行十次)。

public class InsertTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		InsertBook();  
		patchInsertBook();
	}
	
	public static void InsertBook() {
		try {
//			完成类的加载 com.mysql.jdbc.Driver类来源于(pom文件)的jar包
			Class.forName("com.mysql.jdbc.Driver"); 
			System.out.println("注册驱动成功");
		} catch (ClassNotFoundException e) {
			System.out.println("注册驱动失败");
			e.printStackTrace();
		} 
		
		String url = "jdbc:mysql://localhost:3306/test";  
		Connection conn = null;
		try {
//		构建桥梁 url 用户名密码(mysql数据库的)
			conn = DriverManager.getConnection(url, "root", "12345");
			
			String sql = "insert into t_book(tookid, bookname, price) values(?,?,?)";

//			创建数据库执行者
			PreparedStatement pstmt = conn.prepareStatement(sql);
			
			int tookid = 0507;
			String bookName = "初九";
			double price = 1000000;
			
			pstmt.setInt(1, tookid);
			pstmt.setString(2, bookName);
			pstmt.setDouble(3, price);
			
			int result = pstmt.executeUpdate();
			
			System.out.println("操作成功");
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				if(null != conn) {
					try {
						conn.close();
						System.out.println("成功关闭连接");
						} catch (SQLException e) {
								e.printStackTrace();
						}
				}
			}
	}
	
	public static void patchInsertBook() {
//		批量插入
		try {
//			完成类的加载 com.mysql.jdbc.Driver类来源于(pom文件)的jar包
			Class.forName("com.mysql.jdbc.Driver"); 
			System.out.println("注册驱动成功");
		} catch (ClassNotFoundException e) {
			System.out.println("注册驱动失败");
			e.printStackTrace();
		} 
		
		String url = "jdbc:mysql://localhost:3306/test";  
		Connection conn = null;
		try {
//		构建桥梁 url 用户名密码(mysql数据库的)
			conn = DriverManager.getConnection(url, "root", "12345");
			
			String sql = "insert into t_book(tookid, bookname, price) values(?,?,?)";

//			创建数据库执行者
			PreparedStatement pstmt = conn.prepareStatement(sql);
			
			String bookName = "十九";
			double price = 57;
			
			for(int i = 200; i < 210; i++) {
				pstmt.setInt(1, i);
				pstmt.setString(2, bookName);
				pstmt.setDouble(3, price);
				pstmt.addBatch();  // 批量保存
			}
			
			pstmt.executeBatch();
			
			System.out.println("操作成功");
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				if(null != conn) {
					try {
						conn.close();
						System.out.println("成功关闭连接");
						} catch (SQLException e) {
								e.printStackTrace();
						}
				}
			}
		
	} 
}
------------------------ResultSetMetaData--------------------------
  • ResultSet可以用来承载所有的select语句返回的结果集

  • ResultSetMetaData来获取ResultSet返回的属性(eg:每行名字类型等等)
    (1) getColumnCount() 返回结果的列数
    (2) getColumnClassName(i) 返回第i列的数据的java类名 )

    getColumnName,getClassName
    

    在这里插入图片描述
    (3) getColumnTypeName(i) 返回第i列的数据库类型名称

    getColumnName,getTypeName
    

    在这里插入图片描述

    (4) getColumnType(i) 返回第i列SQL类型

    getColumnName,getColumnType
    

    在这里插入图片描述
    (5)getColumnName(i) 返回第i列的列名 (bookid)
    注意JDBC中很多操作从1开始而非0

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

public class ResultSetMetaDataTest {

	public static void main(String[] args) {
		try {
//			完成类的加载 com.mysql.jdbc.Driver类来源于(pom文件)的jar包
			Class.forName("com.mysql.jdbc.Driver"); 
			System.out.println("注册驱动成功");
		} catch (ClassNotFoundException e) {
			System.out.println("注册驱动失败");
			e.printStackTrace();
		} 
		
		String url = "jdbc:mysql://localhost:3306/test";  
		Connection conn = null;
		try {
//		构建桥梁 url 用户名密码(mysql数据库的)
			conn = DriverManager.getConnection(url, "root", "12345");
			
//			创建数据库执行者
			Statement stmt = conn.createStatement();
			System.out.println("创建Statement成功!");
			
//			执行SQL语句并返回结果到ResultSet
			ResultSet rs = stmt.executeQuery("select tookid, bookname, price from t_book order by tookid");
			
//			获取结果集的元数据
			ResultSetMetaData meta = rs.getMetaData();
			int cols = meta.getColumnCount(); // 有多少列
			for(int i = 1; i <= cols; i++) {
				System.out.println(meta.getColumnName(i) + " , " + meta.getColumnTypeName(i));
			}
					
			rs.close();
			stmt.close();
			
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				if(null != conn) {
					try {
						conn.close();
						System.out.println("成功关闭连接");
						} catch (SQLException e) {
								e.printStackTrace();
						}
				}
			}
		
	}

}

在这里插入图片描述

数据库连接池

运用共享技术来实现数据库连接池(享元模式)
(桥梁构建不容易,单次使用成本高)

  • 降低系统中数据库连接Connection对象的数量
  • 降低数据库服务器的连接响应消耗
  • 提高Connction获取的响应速度

享元模式:一个系统中存在大量的相同的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式减少系统中对象的数量

C3P0数据库连接池
Druid数据库连接池

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值