概述
简单入门,希望这篇博客让你了解 JDBC的使用和操作!
JDBC
- 一、初识 JDBC
- 二、初使 JDBC
- 1.JDBC 的使用步骤
- 2.单元测试
- 3.创建工具类DBUtils对参数配置初步封装
- 4.配置文件的了解和应用
- 5.连接池的使用
- 6.对工具类 DBUtils的改良最终版
- 7.登录注册简单功能简单实现
- 1.注册
- 2.登录
- 三、sql注入异常
- 1.什么是sql注入异常
- 2.statement对象执行sql语句原理
- 3.PreparedStatement对象的了解及使用
- 4.statement和PreparedStatement对象对比
- 四、statement和PreparedStatement的对比使用
- 1.批量操作
- 2.分页练习
- 3.获取自增主键值
- 五、球队球员案例练习
一、初识 JDBC
- JavaDataBaseConnectivity java:数据库连接
- 学习JDBC主要学习的就是如果在java代码中执行SQL语句
- JDBC是Sun公司提供的一套Java语言和数据库进行连接的API(Application Programma Interface 应用程序编程接口)
- 为什么使用JDBC?
答: 如果没有JDBC接口,Java程序员有可能每一种数据库都学习一套全新的方法,Sun公司为了避免Java程序员做无用功,通过JDBC接口规范了各个数据库厂商的方法名, 各个数据库厂商只需要根据JDBC接口中的方法名去写各自的实现类(驱动)即可, 只要遵循了JDBC的标准写代码, 即使将来换数据库代码都不需要做任何改动. - 简单总结:JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现。各种不同类型的数据库都依这种规范有相应的实现,都是由java类和接口组成。
二、初使 JDBC
1.JDBC 的使用步骤
- 下面我们来看看 JDBC 的使用步骤,由浅入深,我会使用 JDBC结合案例来让大家更明白,清楚
- 如何使用JDBC?
1、创建maven工程
2、在pom.xml文件中导入jdbc的Mysql实现依赖
<!-- 连接MySQL数据库的依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
3、创建cn.tedu包 并写第一个Demo01.java
- 代码如下:
public class Demo01 {
public static void main(String[] args) throws Exception{
//1.注册驱动 通过反射加载驱动类 异常抛出并改成最高异常
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true","root","root");
System.out.println(conn);
//3.创建执行sql语句的对象
Statement s = conn.createStatement();
//4.执行sql语句
String sql = "create table jdbct1(id int,name varchar(10))";
s.execute(sql);//execute:执行
System.out.println("执行完成!");
//5.关闭资源
conn.close();
}
}
下面我们来讲解下上述代码每一步都在做什么,可以分五个步骤
1.注册驱动 通过反射加载驱动类,驱动加载好之后就可以使用jdbc了
Class.forName("com.mysql.cj.jdbc.Driver");
2.获取数据库连接对象,我们是通过java代码操作数据库,所以首先要连接到数据库才可以,下面对连接参数进行说明
"jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true","root","root"
上面的参数部分大部分都是固定不变的,有的则需要我们去更改,说明:
jdbc:mysql://localhost:3306/newdb3?......"root","root"
- 其中mysql这里写的是你所使用的数据库,大部分都用的mysql 这里就不用更改了,当然如果你用的别的数据库,这里就需要更改下;newdb3:这是你要使用的库名,我使用的是我创建的 newdb3 这个库,大家不必和我一样;“root”,“root”:第一个root 就是数据库管理员用户名,默认都是 root 不用更改,第二个 root 就是你登录数据库时候需要的密码,我的密码是 root,大家填写自己密码就好!
3.创建执行sql语句的对象(后面我们还会学习通过PreparedStatement对象,执行sql语句,这里先介绍Statement )
Statement s = conn.createStatement();
4、执行sql语句,这里我们在newdb3库下创建表jdbt1
String sql = "create table jdbct1(id int,name varchar(10))";
s.execute(sql);//execute:执行
- 大家可以更改上面的sql语句,多练习执行下,然后在终端(DOS窗口)/数据库可视化工具里面进行查看,我这里就不演示了,内容相对简单!
2.单元测试
- 单元测试:在一个由public修饰的无返回值的方法上添加 @test ,此方法类似于main方法,使用方便,我们可以在一个类里面写多个测试案例,下面写几个栗子给大家看看就明白了
我们首先要在工程中添加依赖:
<!--JUnit 单元测试框架-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
栗子:
public class Demo03 {
@Test
public void test01() throws Exception {
System.out.println("单元测试01");
//增
Class.forName("com.mysql.cj.jdbc.Driver");
Connection cnn = DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true","root","root");
Statement s = cnn.createStatement();
s.executeUpdate("insert into emp(empno,ename) values (101,'Tom')");
System.out.println("插入数据成功");
cnn.close();//关闭资源
}
@Test
public void test02() throws Exception{
System.out.println("单元测试02");
//改
Class.forName("com.mysql.cj.jdbc.Driver");
Connection cnn = DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true","root","root");
Statement s = cnn.createStatement();
s.executeUpdate("update emp set ename='单元测试2' where ename='Tom'");
System.out.println("修改数据成功");
cnn.close();//关闭资源
}
@Test
public void test03() throws Exception{
System.out.println("单元测试03");
//删
Class.forName("com.mysql.cj.jdbc.Driver");
Connection cnn = DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true","root","root");
Statement s = cnn.createStatement();
s.executeUpdate("delete from emp where ename='单元测试2'");
System.out.println("删除数据成功");
cnn.close();//关闭资源
}
@Test
public void test04() throws Exception{
System.out.println("单元测试04");
//查
Class.forName("com.mysql.cj.jdbc.Driver");
Connection cnn = DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true","root","root");
Statement s = cnn.createStatement();
//执行查询的sql语句
ResultSet resultSet = s.executeQuery("select ename,sal from emp");
//遍历结果集对象
while (resultSet.next()){//next返回值判断是否有下一条数据
//通过字段位置获取数据
String name1 = resultSet.getString(1);
double sal1 = resultSet.getDouble(2);
System.out.println(name1+":"+sal1);
}
cnn.close();
}
}
大家肯定也发现,我们Statement执行SQL语句的对象有三种,我们分别看看这三种的区别:
- execute(sql); 此方法可以执行任意SQL语句,但是推荐执行DDL(数据定义语言) 数据库相关SQL和表相关SQL
- executeUpdate(sql); 执行增删改相关的SQL语句
- ResultSet rs = executeQuery(sql); 执行查询相关的SQL语句 ,ResultSet是结果集对象,里面装着查询回来的所有数据
3.创建工具类DBUtils对参数配置初步封装
- 我们在使用 JDBC 时候,注册驱动,获取数据库连接对象 内容都是不变的,参数还那么长,写起来很麻烦,所以我们把不变的这一部分给它封装到一个工具类里面
DBUtils 工具类:
//工具类
public class DBUtils {
public static Connection getConn() throws Exception{
Class.forName("com.mysql.cj.jdbc.Driver");
Connection cnn = DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true","root","root");
return cnn;
}
}
- 这下我们在使用 JDBC 时候,我们就可以调用这个工具类,获取数据库连接就好,下面写个栗子测试下:
Demo04:
public class Demo04 {
public static void main(String[] args) {
//获取连接
try(Connection cnn = DBUtils.getConn()){
Statement s = cnn.createStatement();
ResultSet rs = s.executeQuery("select ename from emp");
//遍历结果集
while (rs.next()){
String name = rs.getString(1);
System.out.println(name);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
- 补充:有人可能好奇,为什么我把获取数据库连接这部分代码
Connection cnn = DBUtils.getConn()
- 写到 try 块前的括号里面了,因为在 Java7后,try()括号里面的声明和初始化资源,在try块语句结束后,会自动关闭,而括号里面的资源实现类必须实现 AutoCloseable或者Closeable接口;也就是我们不用在 finally块里面再关闭了,减少代码量!
4.配置文件的了解和应用
什么是配置文件?
- 简单说:配置文件就是一个存放 key-value 结构的容器,一般不能乱碰,因为 key-value 键值对一般记录着程序的运行参数,而且很多都是初始化参数,一般这些参数自程序开始运行,到程序结束死亡,且key-value键值对的值都是定值!
我们来自己写个简单的配置文件,然后运行测试下
- 1、在工程的 resources 目录下创建 my.properties 配置文件
操作:鼠标点击 resources 目录,右键 new 然后选择 Resource bundle,起名 my.properties 内容如下:
创建类 Demo02 访问配置文件中信息:
分为四个步骤: - 1、创建属性配置对象
- 2、创建配置文件的输入流对象 通过类加载器得到resources目录下输入流对象
- 3、把文件加载到属性对象
- 4、开始读取配置文件中的数据 获取数据时候只能获取得到字符串类型
public class Demo02 {
public static void main(String[] args) throws IOException {
//创建属性配置对象
Properties p = new Properties();
//创建配置文件的输入流对象 通过类加载器得到resources目录下输入流对象
InputStream ips = Demo02.class.getClassLoader().getResourceAsStream("my.properties");
//把文件加载到属性对象
p.load(ips);
//开始读取配置文件中的数据 获取数据时候只能获取得到字符串类型
String name = p.getProperty("name");
String age = p.getProperty("age");
System.out.println(name+":"+age);
}
}
运行结果:
- 简单了解了和使用了配置文件后,我们就要对我们 JDBC 代码参数部分进行改进;我们参数部分其实也可以以成键值对的形式表示,我们就可以写一个配置文件把它们写入
实现: 在工程的 resources 目录下创建 jdbc.properties 配置文件,内容如下:
jdbc.properties :
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
db.username=root
db.password=root
db.maxActive=10
db.initialSize=2
5.连接池的使用
数据库连接池 DBCP
- DataBaseConnectionPool
- 为什么使用DBCP?
如果没有数据库连接池,每一次业务请求都需要对应一次数据库的开关连接,一万次请求需要有一万次开关连接, 频繁开关连接浪费资源, 通过连接池可以将连接重用,从而提高执行效率
- 工作原理: 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。当用户第一次获取连接时,会先请求一定数量(初始链接数量)链接池中,并且会记录每个连接的初始(未使用)时间,然后再将链接池中的连接给有需要的用户。当缓冲池中初始连接用完了,链接池会判断所创建的连接数量是否大于最大链接数如果不大于则可以继续创建连接给请求的用户使用(创建的新连接的个数可自己控制,链接池中有相应的增长参数)。如果已经到到最大链接数则当前用户需要等待直到有用户使用完之后关闭连接,这个用户才可以重复使用。当我们开始使用链接池的时候链接池内部就会进行计时(超时时间),每隔空闲链接的存活时间就会对链接池内部的连接进行一次清理。把所有(当前时间 - 链接最后使用的时间 )> 空闲链接的存活时间的连接释放掉。
如何使用数据库连接池
- 1、在工程中添加以下依赖
<!-- 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
- 2、通过以下代码初始化连接池对象 并获取连接
步骤:创建连接池对象、设置数据库连接信息、设置初始连接数量、设置最大连接数量、获取连接 异常抛出
public class Demo03 {
public static void main(String[] args) throws SQLException {
//创建连接池对象
DruidDataSource ds = new DruidDataSource();
//设置连接池信息
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/newdb3?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true");
ds.setUsername("root");
ds.setPassword("root");
//设置连接池初始化连接数量
ds.setInitialSize(3);
ds.setMaxActive(5);//设置最大连接数量
//获取连接 异常抛出
Connection conn = ds.getConnection();
System.out.println(conn);
}
}
6.对工具类 DBUtils的改良最终版
- 上面我们把 JDBC 参数配置在配置文件里面,以键值对形式存储;其次我们使用连接池也要用到 JDBC 的参数;配置文件就一份,且配置文件要在程序执行时初始化,所以我们把它放在 DBUtils工具类的静态块中,如下:
public class DBUtils {
private static DruidDataSource ds;
static {
//1、读取配置文件
Properties p = new Properties();
InputStream ips = DBUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
p.load(ips);
} catch (IOException e) {
e.printStackTrace();
}
String driver = p.getProperty("db.driver");
String uri = p.getProperty("db.url");
String username = p.getProperty("db.username");
String password = p.getProperty("db.password");
//2、创建连接池
//从配置文件中:读取连接池相关信息
String maxsize = p.getProperty("db.maxActive");
String initsize = p.getProperty("db.initialSize");
//创建连接池对象
ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(uri);
ds.setUsername(username);
ds.setPassword(password);
ds.setInitialSize(Integer.parseInt(initsize));
ds.setMaxActive(Integer.parseInt(maxsize));
}
public static Connection getConn() throws Exception{
Connection cnn = ds.getConnection();
return cnn;
}
}
下面我们获取数据库连接就调用这个:工具类 DBUtils 就好
7.登录注册简单功能简单实现
- 1、创建表
表里面有:id、username 用户名,password 密码
create table user(id int primary key auto_incremant,username varchar(50),password varchar(50));
1.注册
注册及就是从键盘获取用户输入,然后插入到表中
- 代码:
public class Demo04 {
//先创建表create table user(id int primary key auto_incremant,username varchar(50),password varchar(50));
//实现注册功能
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("用户名:");
String username = sc.nextLine();
System.out.println("密码:");
String password = sc.nextLine();
try( Connection conn = DBUtils.getConn()){
Statement s = conn.createStatement();
String sql = "insert into user values(null,'"+username+"','"+password+"')";
s.executeUpdate(sql);
System.out.println("注册成功");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.登录
登录就是从键盘接受用户输入的 用户名和密码 ,然后在数据库找对应的 id,找到了输出登陆成功,否则输出登陆失败
- 代码:
public class Demo05 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("用户名:");
String username = sc.nextLine();
System.out.println("密码:");
String password = sc.nextLine();
try( Connection conn = DBUtils.getConn()){
Statement s = conn.createStatement();
String sql = "select id from user where username = '"+username+"' and password='"+password+"'";
ResultSet resultSet = s.executeQuery(sql);
if (resultSet.next()){//判断是否有数据
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试:我们输入正确的用户名和密码
运行结果正确,登录成功,没有问题,下面我们再测试一组用户名和密码:
- 用户名随意输入,密码输入:
' or '1'='1
运行前,大家可能说,这用户名随意输入的,错了,后面的密码又是类似于乱码的东西,这是什么啊,我们运行看看:
为什么会出现这样的结果,明明输入的用户名和密码都不正确,但是登录成功了,很神奇,这就是下面我们要说的:SQL 注入异常
三、sql注入异常
1.什么是sql注入异常
- 1.结构化查询语言(SQL)是一种用来和数据库交互的文本语言。SQL Injection 就是利用非法的SQL拼接,从而达到入侵数据库的目的。 它的产生主要是由于程序对用户输入的数据没有进行严格的过滤,导致非法的数据库SQL操作语句的执行。 SQL 注入(SQL Injection)攻击具有很大的危害, 攻击者可以利用它读取、修改或者删除数据库内的数据, 获取数据库中的用户名和密码等敏感信息,甚至可以获得 数据库管理员的权限,而且SQL Injection 也很难防范, 一般的防火墙也无法拦截 SQL Injection 攻击。
PreparedStatement对象 能够有效的防止sql注入的攻击。 - 简单总结:往用户写值的地方 写进去了SQL语句导致原有SQL语句的逻辑发生改变,这个过程称为SQL注入,是一个网站存在的安全漏洞,工作中切记不能出现此漏洞
2.statement对象执行sql语句原理
还是上面的 登录代码,我们在sql注入后,打印 sql 语句,看看此时sql语句是什么样子的
- 代码:
public class Demo05 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("用户名:");
String username = sc.nextLine();
System.out.println("密码:");
String password = sc.nextLine();
try( Connection conn = DBUtils.getConn()){
Statement s = conn.createStatement();
String sql = "select id from user where username = '"+username+"' and password='"+password+"'";
ResultSet resultSet = s.executeQuery(sql);
//打印执行的sql语句
System.out.println("注入sql:"+sql);
if (resultSet.next()){//判断是否有数据
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 测试:
分析:password='' or '1'='1' 我们看到1 = 1这是对的,因为加上了or,所以" ’ or ’ 1=1" 是一条永真的sql语句,那么肯定会进入到if语句里面,从而显示登陆成功
! - 除了Statement对象外,我们还有一种PreparedStatement对象,通过PreparedStatement预编译的SQL执行对象解决SQL注入问题,下面来学习
3.PreparedStatement对象的了解及使用
- PreparedStatement为什么能解决SQL注入问题?
- 在使用预编译的SQL执行对象时, 编译SQL语句的时间点由执行SQL语句时提前到创建对象时, 创建时进行编译可以将SQL语句的业务逻辑锁死,这样就避免了被用户输入的内容所影响, 从而解决了注入问题
- 还是用上面的登录代码,不过这次我们把 Statement对象换成PreparedStatement对象,来使用sql注入,看看注入后的sql语句,及运行结果
- 代码:
public class Demo05 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("用户名:");
String username = sc.nextLine();
System.out.println("密码:");
String password = sc.nextLine();
try( Connection conn = DBUtils.getConn()){
//通过预编译SQL执行对象解决SQL注入问题
String sql = "select id from user where username=? and password=?";
PreparedStatement p = conn.prepareStatement(sql);
//替换 ? 内容
p.setString(1,username);
p.setString(2,password);
//执行SQL语句,切记这里不能再传入SQL
ResultSet resultSet = p.executeQuery();
System.out.println("sql"+p);
if (resultSet.next()){//判断是否有数据
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 结果:
- 结果分析:
PreparedStatement对象对把拼装密码看成一个整体,并不会因为or的存在而把拼装密码分开来判断,从而阻止了sql注入异常!
4.statement和PreparedStatement对象对比
有了statement对象,我们为什么还要学习PreparedStatement对象?
- 1、当执行多条同结构的sql语句时,PreparedStatement对象会先提交一个无参数的sql语句进进行编译。
例如:insert into test values(?,?); - 2、同结构的sql语句执行多次,PreparedStatement对象的执行效率要比statment对象高的多。
原因:PreparedStatement对象对于同结构的sql只编译一次。而statment对象有几条sql就需要执行几次。
一个结构的sql语句只执行一次,statment对象更好。原因是:statment对象执行sql时编译和执行一次就完成。而PreparedStatement对象先编译无参数的sql,再提交参数然后再执行。 - 3、实际操作时,更多使用的是PreparedStatement对象。原因就是statment对象容易产生sql注入异常
最后我们写个小案例对上面
四、statement和PreparedStatement的对比使用
1.批量操作
同时执行多条sql语句
- 1、statement
代码:
public class Demo06 {
public static void main(String[] args) {
try(Connection cnn = DBUtils.getConn()){
String sql1="insert into user values(null,'aaa','bbb')";
String sql2="insert into user values(null,'bbb','ccc')";
String sql3="insert into user values(null,'ccc','ddd')";
Statement s = cnn.createStatement();
//将多条SQL语句添加到批量操作 在内存中记录需要执行的SQL语句
s.addBatch(sql1);
s.addBatch(sql2);
s.addBatch(sql3);
//执行批量操作
s.executeBatch();
System.out.println("执行完成");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 2、PreparedStatement
代码:
//批量操作
public class Demo07{
public static void main(String[] args) {
try(Connection conn = DBUtils.getConn()){
String sql = "insert into user values(null,?,?)";
PreparedStatement p = conn.prepareStatement(sql);
//遍历100次 用户添加数据
for (int i = 1;i<100;i++){
//替换 ? 内容
p.setString(1,"name"+i);
p.setString(2,"pw"+i);
//添加到批量操作
p.addBatch();
if (i%20==0){//每隔20条批量执行一次,避免出现内存溢出
p.executeBatch();//执行批量操作
}
}
p.executeBatch();//这个执行批量操作是 执行剩下的没有执行的sql语句,如果sql语句恰好为20的倍数,则sql
//就在里面的executeBatch()执行完了
System.out.println("完成");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.分页练习
查询指定页的指定条数据
- PreparedStatement
代码:
public class Demo08 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入查询的页数");
int page = sc.nextInt();
System.out.println("请输入查询的条数");
int count = sc.nextInt();
if (page<1 || count <1){
System.out.println("输入错误");
return;
}
try(Connection conn = DBUtils.getConn()){
String sql = "select * from user limit ?,?";
PreparedStatement ps = conn.prepareStatement(sql);
//替换?内容
ps.setInt(1,(page-1)*count);//跳过的页数
ps.setInt(2,count);
ResultSet rs = ps.executeQuery();
while (rs.next()){
int id = rs.getInt(1);
String name = rs.getString(2);
System.out.println(id+":"+name);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.获取自增主键值
我们在插入数据时候,想获得插入数据的主键值,就可以采用下面方法
- Statement
public class Demo09 {
public static void main(String[] args) {
try(Connection conn = DBUtils.getConn()){
String sql = "insert into user values(null,'libai','abcd')";
Statement s = conn.createStatement();
s.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
//获取自增主键值
ResultSet rs = s.getGeneratedKeys();
//让游标下移一位
rs.next();
//从结果集中取出唯一自增主键
int id = rs.getInt(1);
System.out.println("添加完成!id="+id);
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
五、球队球员案例练习
- 1、创建球队球员表:
create table team(id int primary key auto_increment,name varchar(50));
create table player(id int primary key auto_increment,name varchar(50),team_id int);
- 2、要求:
查询是否存在用户输入的球队名,如果存在查询出球队的id, 如果不存在把球队保存到球队表并且得到自增的id,把得到的球队id和球员名 保存到球员表中
代码:
public class Demo111{
public static void main(String[] args) {
//获取用户输入内容
Scanner sc = new Scanner(System.in);
System.out.println("请输入球队名称");
String teamName = sc.nextLine();
System.out.println("请输入球员名称");
String playerName = sc.nextLine();
try (Connection conn = DBUtils.getConn()){
//查询是否存在球队
String sql = "select id from team where name=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,teamName);
ResultSet rs = ps.executeQuery();
int teamId = 0;
//判断是否查询到 如果查询到内容 此方法返回true
if (rs.next()){//之前保存过
//获取保存的球队id
teamId = rs.getInt(1);
}else{//之前没有保存过
//把球队名保存到team表中
String tsql = "insert into team values(null,?)";
PreparedStatement tps = conn.prepareStatement(tsql,
Statement.RETURN_GENERATED_KEYS);
tps.setString(1,teamName);
tps.executeUpdate();
System.out.println("球队保存完成");
//得到球队自增的id
ResultSet trs = tps.getGeneratedKeys();
trs.next();//游标下移
//取出自增id
teamId = trs.getInt(1);
}
//保存球员
String psql = "insert into player values(null,?,?)";
PreparedStatement pps = conn.prepareStatement(psql);
pps.setString(1,playerName);//替换球员名
pps.setInt(2,teamId);//替换球队id
pps.executeUpdate();
System.out.println("保存球员完成!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
谢谢观看!
最后
以上就是无奈楼房为你收集整理的【Java JDBC使用步骤详解 笔记整理全面】的全部内容,希望文章能够帮你解决【Java JDBC使用步骤详解 笔记整理全面】所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复