Java DataBase Connectivity,简称JDBC,Java数据库连接。是Java语⾔中⽤来规范客户端程序如何来访问数据库的应⽤程序接⼝,JDBC实际上就是Java中的⼀套和数据库交互的API(Application Program Interface,应⽤程序编程接⼝)。
因为Java开发者需要连接多种数据库(Oracle、DB2、MySQL、SQL Server…)为了避免连接每⼀种数据库都学习⼀套新的API,Sun公司提出了JDBC接⼝,各个数据库⼚商根据此接⼝写实现类(驱动),这样Java开发者只需要掌握JDBC接⼝中的⽅法调⽤就可以连接任何数据库
JDBC API主要位于JDK中的java.sql包中(之后扩展的内容位于javax.sql包中),主要包括:
步骤:
1.加载数据库
Class.forName("com.mysql.cj.jdbc.Driver")
2.建立连接
String username="root";
String password = "123456";
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcuseUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC",username,password);
3.执行sql语句
String sql ="sql语句";
4.处理结果集
Statement statement = connection.createStatement();
statement.execute(sql)
5.关闭连接
connection.close();
Statement执⾏SQL语句对象的主要⽅法⻅下。
创建jdbc数据库,将来会在该数据库中创建以下的表。
CREATE DATABASE jdbc CHARACTER SET utf8;
USE jdbc;
# 创建员⼯表
CREATE TABLE emp(
eid INT,
ename VARCHAR(20),
sex CHAR(1),
salary DOUBLE,
hire_date DATE,
dept_name VARCHAR(20)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 添加数据
INSERT INTO emp VALUES(1, '孙悟空', '男', 15000, '2013-02-04', '教学部');
INSERT INTO emp VALUES(2, '猪⼋戒', '男', 10000, '2010-12-02', '教学部');
INSERT INTO emp VALUES(3, '唐僧', '男', 20000, '2008-08-08', '教学部');
INSERT INTO emp VALUES(4, '⽩⻣精', '⼥', 5000, '2015-10-07', '市场部');
INSERT INTO emp VALUES(5, '蜘蛛精', '⼥', 5000, '2011-03-14', '市场部');
INSERT INTO emp VALUES(6, '⽟兔精', '⼥', 3000, '2000-03-14', '市场部');
INSERT INTO emp VALUES(7, '林黛⽟', '⼥', 10000, '2019-10-07', '财务');
INSERT INTO emp VALUES(8, '⻩蓉', '⼥', 3500, '2011-09-14', '财务部');
INSERT INTO emp VALUES(9, '吴承恩', '男', 20000, '2000-03-14', NULL);
INSERT INTO emp VALUES(10, '孙悟饭', '男', 3000, '2020-03-14', '财务部');
INSERT INTO emp VALUES(11, '兔⼋哥', '⼥', 4000, '2010-03-14', '财务部');
-- 创建部⻔表(⼀⽅,主表)
CREATE TABLE department(id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(30),
dept_location VARCHAR(30)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 创建员⼯表(多⽅,从表)
CREATE TABLE employee(
eid INT PRIMARY KEY AUTO_INCREMENT,
ename VARCHAR(20),
age INT,
dept_id INT
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.创建⼀个项⽬名称为【jdbc】的Maven⼯程。
2.在main⽬录下创建⼀个webapp⽂件夹。
3.选择【File】-【project Structure】-【facets】-【点击+号】按钮,添加【Web】选项选择当前⼯程jdbc。
4.修改路径信息,修改成我们创建的webapp⽬录(src/main/webapp)。
5.完成后,在webapp⽬录下会⾃动创建WEB-INF⽬录,并⾃动⽣成web.xml配置⽂件。
添加编译插件,设置jdk编译版本。本教程使⽤jdk11,需要设置编译版本为11,这⾥需要使⽤Maven的插件来设置。在pom.xml⽂件中添加如下配置:
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>11maven.compiler.source>
<maven.compiler.target>11maven.compiler.target>
properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<release>11release>
configuration>
plugin>
plugins>
build>
1.在Maven仓库中搜索mysql的驱动jar包(外⽹:maven.aliyun.com)。
2.将mysql的驱动jar包 Maven依赖 配置到本地⼯程中的pom.xml⽂件中
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.6version>
dependency>
dependencies>
public class jdbcdemo01 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC","root","123456");
System.out.println("连接成功");
String sql ="create table m1(id int primary key auto_increment,name varchar(255))";
Statement statement = connection.createStatement();
statement.execute(sql);
System.out.println();
statement.close();
System.out.println("关闭连接");
}
}
1.在项目中pom.xml文件中导入junit依赖
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
dependency>
2.在com.cy包下创建Demo02类,通过测试⽅法完成增删改查功能。并导⼊单元测试org.junit.Test类。
import org.junit.Before;
import org.junit.Test;
import java.sql.*;
/**
* @author fjp
* @version 1.0
* @description: TODO
* @date 2023/5/16 19:01
*/
public class jdbcdemo02 {
Connection connection;
Statement statement;
@Before
public void before() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
String username = "root";
String password ="123456";
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC", username, password);
statement = connection.createStatement();
}
@Test
public void insert() throws SQLException {
String sql ="insert into emp values (12,'老余','男',1500,'2022-10-1','开发部') " ;
boolean execute = statement.execute(sql);
connection.close();
System.out.println("数据库更新成功!");
}
@Test
public void delete() throws SQLException {
String sql = "delete from emp where eid = 11";
statement.execute(sql);
connection.close();
System.out.println("删除成功!");
}
@Test
public void update () throws SQLException {
String sql = "update emp set ename = '余余' where eid = 12";
statement.execute(sql);
connection.close();
System.out.println("数据更新成功");
}
@Test
public void show() throws SQLException {
String sql="select * from emp where eid = 3";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
String sex = resultSet.getString(3);
double salary = resultSet.getDouble(4);
Date time = resultSet.getDate(5);
String deptName = resultSet.getString(6);
connection.close();
System.out.println("编号:"+id + ",姓名:"+name + ",性别:"+sex+",工资:"+salary + ",入职时间:"+time + ",部门:"+deptName);
}
}
}
DBCP,DataBase Connection Pool,数据库连接池是Apache上的⼀个Java连接池项⽬。DBCP通过连接池预先同数据库建⽴⼀些连接放在内存中(即连接池中),应⽤程序需要建⽴数据库连接时直接到连接池中申请⼀个连接使⽤,⽤完后由连接池回收该连接,从⽽达到连接复⽤,减少资源消耗的⽬的。
1.在pom.xml⽂件导⼊mysql-connector-java和commons-dbcp的jar包。
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.6version>
dependency>
<dependency>
<groupId>commons-dbcpgroupId>
<artifactId>commons-dbcpartifactId>
<version>1.4version>
dependency>
dependencies>
2.创建demo03类,编写数据库连接代码
package dbcp;
import org.apache.commons.dbcp.BasicDataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author fjp
* @version 1.0
* @description: TODO
* @date 2023/5/17 20:43
*/
public class DBCPTest {
public static void main(String[] args) throws SQLException {
//创建数据源对象
BasicDataSource basicDataSource = new BasicDataSource();
//设置数据库连接信息
basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
basicDataSource.setUrl("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=UTF-8");
basicDataSource.setUsername("root");
basicDataSource.setPassword("123456");
//设置初始连接数量
basicDataSource.setInitialSize(5);
//设置最大连接数量
basicDataSource.setMaxActive(5);
//从连接池里面获取连接,异常抛出
Connection connection = basicDataSource.getConnection();
System.out.println("连接成功");
}
}
因为JDBC对数据库的驱动加载、连接获取、释放资源的代码都是相同的,为了提⾼代码的复⽤性,我们可以写⼀个⼯具类,将数据库驱动加载、获取连接、资源释放的代码封装起来。同时,为了提⾼⼯具类的灵活性,可以将数据库的驱动、url、⽤户名、密码等信息以键值对的形式存放在properties⽂件中,⼯具类初始化时从配置⽂件中读取所要连接数据库的信息。当需要更改连接的数据库时,只需要更改配置⽂件即可,⽽不必改写⼯具类的代码。
1.在 src/main/resources ⽬录下创建jdbc.properties⽂件,添加以下配置信息。
# DBCP配置⽂件
# 1.必须项
# 数据库驱动名
driverClassName=com.mysql.jdbc.Driver
# 数据库地址
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=UTF-8
# ⽤户名
username=root
# 密码
password=123456
# 2.可选项(扩展)
# 初始化连接池时的连接数
initialSize=4
# 连接池中可同时连接的最⼤的连接数
maxActive=12
# 连接池中最⼩的空闲的连接数,低于这个数量会被创建新的连接
minIdle=3
# 连接池中最⼤的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不限
maxIdle=5
2.编写DBUtils类
package dbcp;
import org.apache.commons.dbcp.BasicDataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @author fjp
* @version 1.0
* @description: TODO
* @date 2023/5/17 11:14
*/
public class DBUtil {
private static BasicDataSource dataSource;
private static String driverClassName;
private static String url;
private static String username;
private static String password;
private static String initialSize;
private static String maxActive;
private static String minIdle;
private static String maxIdle;
//静态代码块,类初始化加载数据库驱动
static {
//创建数据源对象
dataSource = new BasicDataSource();
//加载jdbc.properties配置文件,通过反射的方式的到文件输入流
InputStream inputStream = DBUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
// 创建读取配置⽂件的properties对象,Properties继承了Hashtable类,Hashtable类实现了Map接⼝
Properties properties = new Properties();
try {
properties.load(inputStream);
driverClassName = properties.getProperty("driverClassName");
url= properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
initialSize = properties.getProperty("initialSize");
maxIdle = properties.getProperty("maxIdle");
minIdle = properties.getProperty("minIdle");
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setInitialSize(Integer.parseInt(initialSize));
dataSource.setMinIdle(Integer.parseInt(minIdle));
dataSource.setMaxIdle(Integer.parseInt(maxIdle));
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//获取数据库连接对象
public static Connection getConnection() throws SQLException {
System.out.println("链接成功");
return dataSource.getConnection();
}
//释放资源
public static void close(Connection connection, Statement statement, ResultSet resultSet){
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.setAutoCommit(true);
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3.测试
package dbcp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author fjp
* @version 1.0
* @description: TODO
* @date 2023/5/17 20:53
*/
public class Test {
public static void main(String[] args) throws SQLException {
Connection connection = DBUtil.getConnection();
String sql ="insert into emp values(25,'余正均','男',500,'2002-1=5','公关部')";
PreparedStatement statement = connection.prepareStatement(sql);
statement.execute();
System.out.println("插入成功");
}
}
java.sql包中的PreparedStatement接⼝继承了Statement接⼝。
PreparedStatement实例包含已编译的SQL语句。这就是使语句“准备好”。包含于PreparedStatement对象中SQL语句可具有⼀个或多个IN参数。IN参数的值在SQL语句创建时未被指定。相反的,该语句为每个IN参数保留⼀个问号(“?”)作为占位符。每个问号的值必须在该语句执⾏之前,通过适当的setXxx()⽅法来提供。
作为Statement的⼦接⼝,PreparedStatement继承了Statement的所有功能。另外它还添加了⼀整套⽅法,⽤于设置发送给数据库以取代IN参数占位符的值。同时,⽅法execute、executeQuery和executeUpdate已被更改以使之不再需要参数。这些⽅法的Statement形式(接受SQL语句参数的形式)不应该⽤于PreparedStatement对象。
以下的代码段(其中conn是Connection对象)创建包含带两个IN参数占位符的SQL语句的PreparedStatement对象
Connection connection = DBUtils.getConnection();
String sql ="select count(*) from t_user where username = ? and password = ?";
PreparedStatement statement= connection.prepareStatement(sql);
statement对象包含语句"SELECT count(*) FROM t_user WHERE username=? and password=?",它已发送给DBMS,并为执⾏作好了准备。
在执⾏PreparedStatement对象之前,必须设置每个"?"参数的值。这可通过调⽤setXxx()⽅法来完成,其中Xxx是与该参数相应的类型。例如,如果参数具有Java类型String,则使⽤的⽅法就是setString()。setXxx()⽅法的第⼀个参数是要设置的参数的序数位置,第⼆个参数是设置给该参数的值
statement.setString(1,"admin");
statement.setString(2,"123456");
⼀旦设置了给定语句的参数值,就可⽤它多次执⾏该语句,直到调⽤clearParameters()⽅法清除它为⽌。在连接的缺省模式下(启⽤⾃动提交),当语句完成时将⾃动提交或还原该语句。
如果基本数据库和驱动程序在语句提交之后仍保持这些语句的打开状态,则同⼀个PreparedStatement可执⾏多次。
setXxx()⽅法中的Xxx是Java类型。它是⼀种隐含的JDBC类型(⼀般SQL类型),因为驱动程序将把Java类型映射为相应的JDBC类型,并将该JDBC类型发送给数据库。开发者的责任是确保将每个IN参数的Java类型映射为与数据库所需的JDBC数据类型兼容的JDBC类型。
1.根据用户输入的内容查询员工的信息
package preparedStatement;
import com.mysql.cj.exceptions.CJOperationNotSupportedException;
import dbcp.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
/**
* @author fjp
* @version 1.0
* @description: TODO
* @date 2023/5/17 21:09
*/
public class PreparedTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = scanner.next();
System.out.println("请输入性别:");
String sex = scanner.next();
try {
Connection connection = DBUtil.getConnection();
String sql = "select * from emp where ename =? and sex = ?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, username);
statement.setString(2, sex);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
int i = resultSet.getInt("eid");
if (i >0) {
System.out.println("查询成功");
System.out.println("id:"+i);
}else {
System.out.println("查询失败");
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2.分页查询
package preparedStatement;
import dbcp.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
/**
* @author fjp
* @version 1.0
* @description: TODO
* @date 2023/5/17 22:57
*/
public class pageLimt {
public static void main(String[] args) throws SQLException {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入请求页数:");
int page = scanner.nextInt();
System.out.println("请输入请求的条数");
int count = scanner.nextInt();
Connection connection = DBUtil.getConnection();
String sql = "select * from emp limit ?,?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, (page-1)*count);
preparedStatement.setInt(2,count);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
String sex = resultSet.getString(3);
System.out.println("编号:"+id + "姓名"+name + "性别"+sex);
}
}
}
1.使用PreparedStatement来代替Statement会使代码的可读性和可维护性提高.
2.PreparedStement极大的提高了安全性,防止sql注入
// 1.Statement写法
String sql = "select count(*) from user where username='" + username + "' and
password='" + password + "'";
String username = "admin";
String password = "123' or '1'='1";
String sql = "select count(*) from user where username='admin' and password='123' or
'1'='1'";
// 2.PreparedStatement写法
// 如果使⽤预编译语句,传⼊的任何内容就不会和原来的语句发⽣任何匹配的关系
String sql = "select count(*) from user where username=? and password=?";
3.由于PreparedStement对象已经预编译过了,所以其执行速度要快于Statement对象.因此多次执行的SQL语句经常创建成PreparedStatement对象,提高效率.
方法 | 描述 |
---|---|
void addBatch(String sql) | 将给定的SQL语句添加到此Statement对象的当前命令列表中,可以提高执行效率 |
void clearBatch() | 清空此Statement对象的当前SQL命令列表 |
int[] executeBatch() | 将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新技术组成的数组 |
1.Statement实现批量操作
public class batchdemo01 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC", "root", "123456");
Statement statement = con.createStatement();
String sql = "update emp set ename = '老6' where eid =2 ";
String sql1 = "insert into emp values(13,'老八','男',500,'1990-6-5','销售部')";
String sql2 = "update emp set ename = '老三' where eid =5 ";
statement.addBatch(sql);
statement.addBatch(sql1);
statement.addBatch(sql2);
statement.executeBatch();
System.out.println("批处理完成");
}
}
2.PreparedStetement实现批处理操作
public class Demo07 {
public static void main(String[] args) {
try (Connection conn = DBUtils.getConnection();) {
String sql = "INSERT INTO emp VALUES(?, ?, '⼥', 5000, '2022-10-07', '市场
部')";
PreparedStatement pstmt = conn.prepareStatement(sql);
for (int i = 1; i <= 11; i++) {
// 替换"?"
pstmt.setInt(1, 1000 + i);
pstmt.setString(2, "user" + i);
// 添加到批量处理
pstmt.addBatch();
// 避免内存溢出
if (i%3 == 0) {
pstmt.executeBatch();
}
}
// 执⾏批量操作
pstmt.executeBatch();
System.out.println("执⾏完成!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
事务就是⼀组操作数据库的动作集合。如果⼀组处理步骤或者全部发⽣或者⼀步也不执⾏,我们称该组处理步骤为⼀个事务。当所有的步骤像⼀个操作⼀样被完整地执⾏,我们称该事务被提交。由于其中的⼀部分或多步执⾏失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态。
事务必须服从ISO/IEC所制定的ACID原则。ACID是原⼦性(atomicity)、⼀致性(consistency)、隔离性(isolation)和持久性(durability)的缩写。JDBC事务是⽤Connection对象控制的。JDBC Connection接⼝(java.sql.Connection)提供了两种事务模式:⾃动提交和⼿⼯提交。java.sql.Connection提供了以下控制事务的⽅法:
使⽤JDBC事务界定时,可以将多个SQL语句结合到⼀个事务中。JDBC事务的⼀个缺点是事务的范围局限于⼀个数据库连接。⼀个JDBC事务不能跨越多个数据库。
public class thingDemo {
public static void main(String[] args) {
Connection con =null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC", "root", "123456");
Statement statement = con.createStatement();
String sql = "update emp set ename = '老jiu' where eid =3 ";
String sql1 = "insert into emp values(14,'光头强','男',5000,'1990-6-5','开发部')";
String sql2 = "update emp set ename = '老三' where eid =5 ";
System.out.println("默认提交方式"+ con.getAutoCommit());
con.setAutoCommit(false);
statement.executeUpdate(sql);
statement.executeUpdate(sql1);
statement.executeUpdate(sql2);
con.commit();
System.out.println("事务提交成功");
} catch (Exception e) {
try {
con.rollback();
System.out.println("有异常,进行回滚");
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
}
RETURN_GENERATED_KEYS:是Statement的属性,表示与数据库的主键值绑定,在使⽤的时候可以取出来。getGeneratedKeys():是Statement的⽅法,获取⽣成键的结果集。在使⽤Statement.RETURN_GENERATED_KEYS时,需要特别注意,被操作的数据表主键Id必须设置AUTO_INCREMENT属性。数据库⾃增的Id和⼿动插⼊的Id均可正常返回。
1.根据⽤户输⼊的部⻔名称和部⻔地址实现数据插⼊操作,并返回⾃动⽣成的主键值。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Demo09 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输⼊部⻔名称:");
String deptName = sc.nextLine();
System.out.println("请输⼊部⻔地址:");
String deptLocation = sc.nextLine();
try {
Connection conn = DBUtils.getConnection();
String sql = "INSERT INTO department VALUES (null, ?, ?)";
// RETURN_GENERATED_KEYS表示与数据库的主键值绑定,在使⽤的时候可以取出来
PreparedStatement pstmt = conn.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, deptName);
pstmt.setString(2, deptLocation);
pstmt.executeUpdate();
// 获取⽣成键的结果集
ResultSet rs = pstmt.getGeneratedKeys();
while (rs.next()) {
int id = rs.getInt(1);
System.out.println("执⾏完成:" + id);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.根据⽤户输⼊的部⻔信息保存部⻔,并将⾃动返回的部⻔id作为员⼯的部⻔进⾏数据的保存操作。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Demo10 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输⼊部⻔名称:");
String deptName = sc.nextLine();
System.out.println("请输⼊部⻔地址:");
String deptLocation = sc.nextLine();
System.out.println("请输⼊员⼯姓名:");
String empName = sc.nextLine();
System.out.println("请输⼊员⼯年龄:");
int empAge = sc.nextInt();
try(Connection conn = DBUtils.getConnection();) {
String sql1 = "INSERT INTO department VALUES (null, ?, ?)";
// RETURN_GENERATED_KEYS表示与数据库的主键值绑定,在使⽤的时候可以取出来
PreparedStatement pstmt1 = conn.prepareStatement(sql1,
Statement.RETURN_GENERATED_KEYS);
pstmt1.setString(1, deptName);
pstmt1.setString(2, deptLocation);
pstmt1.executeUpdate();
// 获取⽣成键的结果集
ResultSet rs = pstmt1.getGeneratedKeys();
while (rs.next()) {
int deptId = rs.getInt(1);
// 得到部⻔id后开始保存员⼯
String sql2 = "INSERT INTO employee VALUES (null, ?, ?, ?)";
PreparedStatement pstmt2 = conn.prepareStatement(sql2);
pstmt2.setString(1, empName);
pstmt2.setInt(2, empAge);
pstmt2.setInt(3, deptId);
// 执⾏保存
pstmt2.executeUpdate();
System.out.println("保存成功!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.根据⽤户输⼊的部⻔信息查询部⻔是否存在,如果不存在,先插⼊部⻔信息,然后再保存员⼯信息。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Demo11 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输⼊部⻔名称:");
String deptName = sc.nextLine();
System.out.println("请输⼊部⻔地址:");
String deptLocation = sc.nextLine();
System.out.println("请输⼊员⼯姓名:");
String empName = sc.nextLine();
System.out.println("请输⼊员⼯年龄:");
int empAge = sc.nextInt();
try(Connection conn = DBUtils.getConnection();) {
// 查询是否存在⽤户输⼊的部⻔名称
String sql1 = "SELECT id FROM department WHERE dept_name=?";
PreparedStatement pstmt1 = conn.prepareStatement(sql1);
pstmt1.setString(1, deptName);
ResultSet rs1 = pstmt1.executeQuery();
// 存储部⻔id
int deptId = -1;
while (rs1.next()) {
deptId = rs1.getInt(1);
}
// 通过判断deptId值来确定部⻔是否存在
if (deptId == -1) { // 部⻔不存在
String sql2 = "INSERT INTO department VALUES (null, ?, ?)";
// RETURN_GENERATED_KEYS表示与数据库的主键值绑定,在使⽤的时候可以取出来
PreparedStatement pstmt2 = conn.prepareStatement(sql2,
Statement.RETURN_GENERATED_KEYS);
pstmt2.setString(1, deptName);
pstmt2.setString(2, deptLocation);
pstmt2.executeUpdate();
// 获取⽣成键的结果集
ResultSet rs2 = pstmt2.getGeneratedKeys();
while (rs2.next()) {
deptId = rs2.getInt(1);
}
}
// 开始保存员⼯信息
String sql3 = "INSERT INTO employee VALUES (null, ?, ?, ?)";
PreparedStatement pstmt3 = conn.prepareStatement(sql3);
pstmt3.setString(1, empName);
pstmt3.setInt(2, empAge);
pstmt3.setInt(3, deptId);
// 执⾏保存
pstmt3.executeUpdate();
System.out.println("保存成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
元数据(MetaData)是关于数据的数据。元数据是描述数据库内数据的结构和建⽴⽅法的数据。元数据分类:数据库元数据和表的元数据
import java.sql.*;
public class Demo12 {
public static void main(String[] args) {
try (Connection conn = DBUtils.getConnection();) {
// 获取数据库元数据
DatabaseMetaData dbmd = conn.getMetaData();
System.out.println("数据库⼚商:" + dbmd.getDatabaseProductName());
System.out.println("驱动版本:" + dbmd.getDriverVersion());
System.out.println("连接地址:" + dbmd.getURL());
System.out.println("⽤户名:" + dbmd.getUserName());
// 获取表的元数据信息需要先进⾏查询操作
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM emp");
// 获取表的元数据
ResultSetMetaData rsmd = rs.getMetaData();
// 获取表字段数量
int count = rsmd.getColumnCount();
// 遍历每个字段的名字和类型
for (int i = 1; i <= count; i++) {
String name = rsmd.getColumnName(i);
String type = rsmd.getColumnTypeName(i);
System.out.println(name + ":" + type);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
JDBC: Java DataBase Connectivity java数据库连接和执行SQL语句的API
JNDI: Java Naming and Directory Interface ,Java命名和目录接口,JNDI是指使用数据源连接数据库的这种方式,简单的可以将JDNI理解成所有DataScource的集合
DBCP: DataBase Connection Pool,数据库连接池,数据连接池就是连接数据库进程的集合,一般的SQL执行都是"建立数据库连接-执行SQL-关闭数据库",对于平凡的数据库连接应用,这样反复建立连接-关闭连接是非常消耗系统资源的
DataSource: 数据源,就是将IP,数据库,用户名,密码,封装起来对外只提供一个JNDI名称,在应用中只要调用这个JNDI就能连接数据库,而不需要在代码中写入用户名,密码等.这样的好处是,当用户名.密码乃至数据库发生变化时,只需要去修改JNDI的xml文件而不需要修改代码