我是一个从汽车行业转行IT的项目经理,我是Edward,如想了解更多,请关注我的公众号【转行项目经理的逆袭之路】。 JavaDataBaseConnectivity Java数据库连接,JDBC是sun公司提供的一套通过Java语言和数据库进行连接的相关API(Application Program Interface)
为什么使用JDBC: 在工作中Java语言有可能连接多种不同的数据库,为了避免Java程序员每一种数据库都学习套新的方法,Sun公司定了一套方法的声明(JDBC),各个数据库厂商根据此接口写实现类(驱动),这样Java程序员只需要学习JDBC中方法的调用即可访问任何数据库,如果严格按照JDBC标准所写的代码就算将来换数据库,代码不需要改变。
如何使用JDBC
创建maven工程
在pom.xml中添加以下mysql的相关坐标
<!-- 连接MySQL数据库的依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency
创建Demo01.java添加以下代码
//1. 注册驱动 通知编译器使用的是什么数据库 抛出异常
//Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获取数据库连接 参数介绍:1.url连接地址 2.用户名 3.密码(自己mysql密码)
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 jdbct2(name varchar(10),age int)";
s.execute(sql);//执行SQL
System.out.println("执行成功!");
//5. 关闭资源
conn.close();
Statement执行SQL语句的对象
增删改查
execute(sql) 用于执行数据库相关和表相关的操作
executeUpdate(sql) 用于执行增删改
executeQuery(sql) 用于执行查询
数据库连接池
为什么使用数据库连接池? 如果不使用连接池每一次客户端发出的业务请求都需要对应一次数据库连接,如果有一万次请求就有一万次数据库连接的建立和断开,频繁的开关连接会影响程序的执行效率,通过数据库连接池可以将数据库连接进行复用,从而提高执行效率.
如何使用?
//创建连接池对象
DruidDataSource ds = new DruidDataSource();
//设置数据库连接信息
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
//设置初始连接数量
ds.setInitialSize(Integer.parseInt(initSize));
//设置最大连接数量
ds.setMaxActive(Integer.parseInt(maxSize));
//从连接池对象中获取连接 异常抛出
Connection conn = ds.getConnection();
读取*.properties配置文件
//创建读取配置文件的属性对象
Properties p = new Properties();
//得到文件输入流 这种写法会自动去src/main/resources目录下找文件
InputStream ips = Demo03.class.getClassLoader()
.getResourceAsStream("my.properties");
//把文件输入流交给属性对象
p.load(ips);
//读取数据
String name = p.getProperty("name");
//getProperty方法只能读取字符串
String age = p.getProperty("age");
System.out.println(name+":"+age);
注册和登录功能
创建用户表 use newdb3; create table user(id int primary key auto_increment,username varchar(20),password varchar(20))charset=utf8;
SQL注入问题:
当你输入:
形成:select count(*) from user where username=‘asdf’ and password=’’ or ‘1’=‘1’
无论输入什么用户名都可以登录成功。
Statement和PreparedStatement
如果执行的SQL语句中存在变量,为了避免SQL注入所以使用PreparedStatement
如果SQL语句中没有变量则使用Statement
批量操作
批量操作就是将多条SQL语句执行时的多次网络数据传输合并成一次传输,从而提高执行效率
package cn.tedu;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
public class Demo06 {
public static void main(String[] args) {
//获取连接
try (Connection conn = DBUtils.getConn();) {
// String sql1 = "insert into user values(null,'刘备','123')";
// String sql2 = "insert into user values(null,'关羽','123')";
// String sql3 = "insert into user values(null,'张飞','123')";
// Statement s = conn.createStatement();
//// s.executeUpdate(sql1);
//// s.executeUpdate(sql2);
//// s.executeUpdate(sql3);
// //通过批量操作将多次数据传输合并成一次
// s.addBatch(sql1);
// s.addBatch(sql2);
// s.addBatch(sql3);
// //执行批量操作
// s.executeBatch();
// System.out.println("执行完成!");
//PreparedStatement批量操作
String sql = "insert into user values(null,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
for (int i = 1; i <= 100; i++) {
ps.setString(1, "name"+i);
ps.setString(2, "pw"+i);
//添加到批量操作
ps.addBatch();
//每隔20次执行一次,避免内存溢出
if (i%20==0) {
ps.executeBatch();
}
}
//执行批量操作,预留一次以免还有剩余
ps.executeBatch();
System.out.println("执行完毕!");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
分页查询
package cn.tedu;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
public class Demo07 {
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) {
System.out.println("输入错误");
return;
}
//获取连接
try (Connection conn = DBUtils.getConn();) {
String sql = "select username,password from user limit ?,?";
PreparedStatement ps = conn.prepareStatement(sql);
//第一个?代表跳过的条数=(请求页数-1)*条数
ps.setInt(1, (page-1)*count);
ps.setInt(2, count);
//执行查询
ResultSet rs= ps.executeQuery();
while (rs.next()) {
String username = rs.getString(1);
String password = rs.getString(2);
System.out.println(username+":"+password);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
获取自增主键值
创建球队表 create table team(id int primary key auto_increment,name varchar(10))charset=utf8;
创建球员表 create table player(id int primary key auto_increment,name varchar(10),teamId int)charset=utf8;
用获取自增主键值的功能做一个球队球员的关联表
package cn.tedu;
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 teamName = sc.nextLine();
System.out.println("请输入球员名字");
String playerName = sc.nextLine();
// 获取连接
try (Connection conn = DBUtils.getConn();) {
// 先查是否存在这个队
// 直接查id就可以了,有就直接拿到了,不需要再查一次
//只有查询id步骤是分叉的,把teamId拿出来
// 保存球员的步骤可以放到外面去,只用写一次,是共有步骤
//重构是精髓哎~
String sql = "select id from team where name=? ";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, teamName);
ResultSet rs = ps.executeQuery();
int teamId=0;
if (rs.next()) {
teamId = rs.getInt(1);
} else {
// 如果没有再插入
sql = "insert into team values(null,?)";
// 需要用超类调用自增键常数来获取
ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, teamName);
ps.executeUpdate();
// 然后用结果集取回
rs = ps.getGeneratedKeys();
rs.next();
teamId = rs.getInt(1);
// System.out.println("球队id:" + teamId);
}
sql = "insert into player values(null,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, playerName);
ps.setInt(2, teamId);
ps.executeUpdate();
System.out.println("保存完成!");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}