JDBC基础知识
1 概念
jdbc:java database conncetion
通过java程序来连接数据库
sun公司定义的通过java连接所有数据库的一组接口(标准)
jdbc驱动: 不同数据库产品 底层的实现原理/操作不同
不同数据库的厂商 为自己的数据库提供的jdbc的实现类
2 案例
创建web项目
创建测试类
测试插入一行记录
//通过java来连接数据库:jdbc
//1 导入驱动:把jdbc的实现类jar包导入到当前姓名中
// 把第三方jar包在web项目中引用
// 把mysql-connector-java-5.1.15-bin.jar复制到WebContent/WEB-INF/lib下
// 选中jar:点击右键:选择build path
// 把第三方jar包在java项目中引用
// 把mysql-connector-java-5.1.15-bin.jar复制项目名称下
// 选中jar:点击右键:选择build path
//2 准备四大参数(连接数据库的四大参数)
String userName="root";//用户名
String password="root";//密码
String driverName="com.mysql.jdbc.Driver";//驱动类名
String url="jdbc:mysql://localhost:3306/db_11";//mysql服务的路径
//3 注册驱动
Class.forName(driverName);//Unhandled exception type ClassNotFoundException
//4 获取连接
Connection con=DriverManager.getConnection(url, userName, password);
//System.out.println(con);//com.mysql.jdbc.JDBC4Connection@179d3b25
//5 准备sql语句
String sql="insert into stu(sid,sname,sage) values(null,\"测试名字2\",12)";
System.out.println(sql);
//6 获取sql语句发送器对象:Statement
Statement sta=con.createStatement();
//7 通过sql语句发送器对象的executeXxx方法把sql语句发送给数据库 获取影响的行数
int hang=sta.executeUpdate(sql);
System.out.println("影响的行数="+hang);
//8 关闭资源和连接
sta.close();
con.close();
3 jdbc实现crud
准备数据库
USE db_11;
CREATE TABLE student(
sid INT PRIMARY KEY AUTO_INCREMENT,
sname VARCHAR(11),
sex CHAR(1),
sage INT,
score FLOAT(4,1),
sdy BOOLEAN
);
INSERT INTO student VALUES(NULL,SUBSTR(UUID(),1,4),IF(RAND()>0.5,"男","女"),TRUNCATE(RAND()*10+15,0),TRUNCATE(RAND()*1000,0),RAND()>0.5);
SELECT * FROM student;
创建实体类:根据表创建
封装数据:实体类----对应表
描述业务:业务类----业务逻辑
指定方面的功能封装:工具类----静态方法
表名/列名--单词之间用下划线分割
类--每个单词首字母大写
属性--除了第一个单词 其他单词首字母大写
实体类要求:根据表创建
1 实现序列化接口
2 属性私有化封装:private 修饰符 提供getset方法
3 重写tostring方法
4 提供必要的constructor 构造方法
5 根据要求重写其他方法---equals方法/hashCode方法
注意:一般属性都用包装类类型
创建jdbc工具类
package com.zhiyou100.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcUtil {
//2 准备四大参数
private static String uname="root";
private static String upwd="root";
private static String url="jdbc:mysql://localhost:3306/db_11";
private static String driverName="com.mysql.jdbc.Driver";
//3 注册驱动
static{
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);//异常转换
}
}
//获取连接
public static Connection getCon(){
try {
return DriverManager.getConnection(url, uname,upwd);
} catch (Exception e) {
throw new RuntimeException(e);//异常转换
}
}
//关闭连接
public static void close(ResultSet set,Statement sta,Connection con){
try {
if(set!=null){
set.close();
}
} catch (Exception e) {
throw new RuntimeException(e);//异常转换
}
try {
if(sta!=null){
sta.close();
}
} catch (Exception e) {
throw new RuntimeException(e);//异常转换
}
try {
if(con!=null){
con.close();
}
} catch (Exception e) {
throw new RuntimeException(e);//异常转换
}
}
public static void main(String[] args) {
System.out.println(getCon());
}
}
创建实现student的crud类
package com.zhiyou100.day01;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.zhiyou100.entity.Student;
import com.zhiyou100.util.JdbcUtil;
public class Test02Crud {
public static void main(String[] args)throws Exception{
//addOne(new Student( "新来的2", "妖", 29, 29f, true));
//deleteOne(1);
//updateOne(new Student(2, "无名氏", "妖", 11, 44f, true));
//System.out.println(getOne(3));
System.out.println(getAll());
}
//把参数student对象的信息添加到表中
public static void addOne(Student stu)throws Exception{
//1 的人jar包
//2 准备四大参数
//3 注册驱动:把启动类加载金内存中
//4 获取连接
Connection con=JdbcUtil.getCon();
//5准备sql语句
String sql="insert into student(sname,sex,sage,sdy,score) "
+ "values('"+stu.getSname()+"','"+stu.getSex()+"',"
+stu.getSage()+","+stu.getSdy()+","+stu.getScore()+")";
System.out.println(sql);
//6 获取sql语句发射器对象
Statement sta=con.createStatement();
//7 执行execute方法 获取结果集
int hang=sta.executeUpdate(sql);
System.out.println("插入"+hang+"行成功!");
//(8 解析结果集)
//9 关闭连接
JdbcUtil.close(null, sta, con);
}
//根据主键删除
public static void deleteOne(int sid)throws Exception{
//4 获取连接
Connection con=JdbcUtil.getCon();
//5准备sql语句
String sql="delete from student where sid="+sid;
System.out.println(sql);
//6 获取sql语句发射器对象
Statement sta=con.createStatement();
//7 执行execute方法 获取结果集
int hang=sta.executeUpdate(sql);
System.out.println("删除"+hang+"行成功!");
//(8 解析结果集)
//9 关闭连接
JdbcUtil.close(null, sta, con);
}
//根据主键修改:更改与参数stu的sid值相同的列
public static void updateOne(Student stu)throws Exception{
//4 获取连接
Connection con=JdbcUtil.getCon();
//5准备sql语句
String sql="update student set sname='"+stu.getSname()+"',sex='"+stu.getSex()+"',"
+ "score="+stu.getScore()+",sdy="+stu.getSdy()+",sage="+stu.getSage()+" where"
+ " sid="+stu.getSid();
System.out.println(sql);
//6 获取sql语句发射器对象
Statement sta=con.createStatement();
//7 执行execute方法 获取结果集
int hang=sta.executeUpdate(sql);
System.out.println("修改"+hang+"行成功!");
//(8 解析结果集)
//9 关闭连接
JdbcUtil.close(null, sta, con);
}
/*
* ResultSet:结果集
* 方法: 1 boolean next();判断光标是否还有行可以遍历
* 2 xxx getXxx(String columnName);根据列名获取值
* xxx getXxx(int columnIndex);根据列索引获取值
* 3 void close();关闭
* */
//查询: 根据sid获取一个
public static Student getOne(int sid)throws Exception{
Student stu=null;
//4 获取连接
Connection con=JdbcUtil.getCon();
//5准备sql语句
String sql="select * from student where sid="+sid;
System.out.println(sql);
//6 获取sql语句发射器对象
Statement sta=con.createStatement();
//7 执行execute方法 获取结果集
ResultSet set=sta.executeQuery(sql);
//(8 解析结果集)
if(set.next()){
//获取参数
String sname=set.getString("sname");
sname=set.getString(2);
String sex=set.getString("sex");
sex=set.getString(3);
float score=set.getFloat("score");
score=set.getFloat(5);
int sage=set.getInt("sage");
sage=set.getInt(4);
boolean sdy=set.getBoolean("sdy");
sdy=set.getBoolean(6);
stu=new Student(sid, sname, sex, sage, score, sdy);
}
//9 关闭连接
JdbcUtil.close(null, sta, con);
return stu;
}
//查询所有
public static List<Student> getAll()throws Exception{
List<Student> list=new ArrayList<Student>();
//4 获取连接
Connection con=JdbcUtil.getCon();
//5准备sql语句
String sql="select * from student";
System.out.println(sql);
//6 获取sql语句发射器对象
Statement sta=con.createStatement();
//7 执行execute方法 获取结果集
ResultSet set=sta.executeQuery(sql);
//(8 解析结果集)
while(set.next()){
//获取参数
int sid=set.getInt("sid");
String sname=set.getString("sname");
sname=set.getString(2);
String sex=set.getString("sex");
sex=set.getString(3);
float score=set.getFloat("score");
score=set.getFloat(5);
int sage=set.getInt("sage");
sage=set.getInt(4);
boolean sdy=set.getBoolean("sdy");
sdy=set.getBoolean(6);
Student stu=new Student(sid, sname, sex, sage, score, sdy);
list.add(stu);
}
//9 关闭连接
JdbcUtil.close(null, sta, con);
return list;
}
}
4 预处理/预编译 preparedstatement
preparedstatement:是statement的子接口
把sql语句发送给数据库 通过execute方法执行sql语句 获取结果集/影响的行数
通过preparedstatement实现crud
package com.zhiyou100.day01;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.zhiyou100.entity.Student;
import com.zhiyou100.util.JdbcUtil;
public class Test03PreparedStatement {
public static void main(String[] args) throws Exception{
//addOne(new Student("韩寒", "男", 11, 12f, true));
//updateOne(new Student(2, "韩梅梅", "女", 33, 44f, true));
//deleteOne(1);
//deleteOne(3);
System.out.println(getOne(2));
System.out.println(getAll());
}
public static List<Student> getAll()throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//2 准备sql模板: 由占位符?替代所有的数据
String sql="select * from student";
//3 获取预编译对象:并关联sql模板
PreparedStatement sta=con.prepareStatement(sql);
//5 执行execute方法
ResultSet set=sta.executeQuery();
//处理结果集
List<Student> list=new ArrayList<Student>();
while(set.next()){
Student stu=new Student();
stu.setSid(set.getInt("sid"));
stu.setSname(set.getString("sname"));
stu.setSex(set.getString("sex"));
stu.setSage(set.getInt("sage"));
stu.setSdy(set.getBoolean("sdy"));
stu.setScore(set.getFloat("score"));
list.add(stu);
}
//6 关闭连接 释放资源
JdbcUtil.close(set, sta, con);
return list;
}
public static Student getOne(int sid)throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//2 准备sql模板: 由占位符?替代所有的数据
String sql="select * from student where sid=?";
//3 获取预编译对象:并关联sql模板
PreparedStatement sta=con.prepareStatement(sql);
//4 给占位符赋值
sta.setInt(1,sid);//参数1:占位符的索引 从1开始 参数2:具体数据
//5 执行execute方法
ResultSet set=sta.executeQuery();
//处理结果集
Student stu=null;
if(set.next()){
stu=new Student();
stu.setSid(set.getInt("sid"));
stu.setSname(set.getString("sname"));
stu.setSex(set.getString("sex"));
stu.setSage(set.getInt("sage"));
stu.setSdy(set.getBoolean("sdy"));
stu.setScore(set.getFloat("score"));
}
//6 关闭连接 释放资源
JdbcUtil.close(set, sta, con);
return stu;
}
public static void deleteOne(int sid)throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//2 准备sql模板: 由占位符?替代所有的数据
String sql="delete from student where sid=?";
//3 获取预编译对象:并关联sql模板
PreparedStatement sta=con.prepareStatement(sql);
//4 给占位符赋值
sta.setInt(1,sid);//参数1:占位符的索引 从1开始 参数2:具体数据
//5 执行execute方法
int hang=sta.executeUpdate();
System.out.println("删除"+hang+"行成功!");
//6 关闭连接 释放资源
JdbcUtil.close(null, sta, con);
}
public static void addOne(Student stu)throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//2 准备sql模板: 由占位符?替代所有的数据
String sql="insert into student(sname,sex,sage,score,sdy) values(?,?,?,?,?)";
//3 获取预编译对象:并关联sql模板
PreparedStatement sta=con.prepareStatement(sql);
//4 给占位符赋值
sta.setString(1, stu.getSname());//参数1:占位符的索引 从1开始 参数2:具体数据
sta.setString(2, stu.getSex());
sta.setInt(3, stu.getSage());
sta.setFloat(4, stu.getScore());
sta.setBoolean(5, stu.getSdy());
//5 执行execute方法
int hang=sta.executeUpdate();
System.out.println("添加"+hang+"行成功!");
//6 关闭连接 释放资源
JdbcUtil.close(null, sta, con);
}
public static void updateOne(Student stu)throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//2 准备sql模板: 由占位符?替代所有的数据
String sql="update student set sname=?,sex=?,sage=?,score=?,sdy=? where sid=?";
//3 获取预编译对象:并关联sql模板
PreparedStatement sta=con.prepareStatement(sql);
//4 给占位符赋值
sta.setString(1, stu.getSname());//参数1:占位符的索引 从1开始 参数2:具体数据
sta.setString(2, stu.getSex());
sta.setInt(3, stu.getSage());
sta.setFloat(4, stu.getScore());
sta.setBoolean(5, stu.getSdy());
sta.setInt(6, stu.getSid());
//5 执行execute方法
int hang=sta.executeUpdate();
System.out.println("修改"+hang+"行成功!");
//6 关闭连接 释放资源
JdbcUtil.close(null, sta, con);
}
}
preparedstatement的优点
/*
* preparedstatement预编译对象和statement相比的优点
* preparedstatement是statement的子接口:都是把sql语句发送给数据库 通过executeXxx方法来执行sql语句
* preparedstatement优点1: 可以防止sql攻击
* statement在执行executeXxx方法时 把sql片段和数据通过字符串拼接后形成一个sql语句发送给数据
* 无法区分数据中伪装的sql片段
* preparedstatement在获取预编译对象时 先发送sql模板给数据库 然后再通过setXxx方法给占位符赋值 发送的是数据
* 数据库可以很容易区分 第一次发送的是sql片段 第二次发送的是数据 数据中伪装的sql片段无法被解析
* preparedstatement优点2: 效率高
* 在多次操作时(批处理), 在获取preparedstatement对象时 数据库只需要对sql模板进行语法 和解析一次即可 每次操作只需要给数据库发送不同的占位符值即可
* 而statement每次在执行execute方法时 发送的是整个sql语句 每次都需要对sql语句进行语法检查和解析
* preparedstatement优点3: preparedstatement不需要sql语句的拼接
* */
public static void main(String[] args)throws Exception{
// TODO Auto-generated method stub
String sname="韩梅梅";
String spwd="123456";
System.out.println(loginPreparedStatement(sname, spwd));
System.out.println(loginStatement(sname, spwd));
sname="韩非子";
spwd="123456";
System.out.println(loginPreparedStatement(sname, spwd));
System.out.println(loginStatement(sname, spwd));
sname="'韩梅梅' or '1'='1'";
spwd="123";
System.out.println(loginPreparedStatement(sname, spwd));
System.out.println(loginStatement(sname, spwd));
}
public static Student loginPreparedStatement(String sname,String spwd)throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//2 准备sql模板: 由占位符?替代所有的数据
String sql="select * from student where sname=? and spwd=?";
//3 获取预编译对象:并关联sql模板
PreparedStatement sta=con.prepareStatement(sql);
//4 给占位符赋值
sta.setString(1, sname);//参数1:占位符的索引 从1开始 参数2:具体数据
sta.setString(2, spwd);
//5 执行execute方法
ResultSet set=sta.executeQuery();
//处理结果集
Student stu=null;
if(set.next()){
stu=new Student();
stu.setSid(set.getInt("sid"));
stu.setSname(set.getString("sname"));
stu.setSex(set.getString("sex"));
stu.setSage(set.getInt("sage"));
stu.setSdy(set.getBoolean("sdy"));
stu.setScore(set.getFloat("score"));
stu.setSpwd(set.getString("spwd"));
}
//6 关闭连接 释放资源
JdbcUtil.close(set, sta, con);
return stu;
}
public static Student loginStatement(String sname,String spwd)throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//2 准备sql模板: 由占位符?替代所有的数据
String sql="select * from student where sname='"+sname+"' and spwd='"+spwd+"'";
System.out.println(sql);
//3 获取sql语句发送器对象对象
Statement sta=con.createStatement();
//5 执行execute方法
//SELECT * FROM student WHERE sname='韩梅梅' OR '1'='1' AND spwd='123';
ResultSet set=sta.executeQuery(sql);
//处理结果集
Student stu=null;
if(set.next()){
stu=new Student();
stu.setSid(set.getInt("sid"));
stu.setSname(set.getString("sname"));
stu.setSex(set.getString("sex"));
stu.setSage(set.getInt("sage"));
stu.setSdy(set.getBoolean("sdy"));
stu.setScore(set.getFloat("score"));
stu.setSpwd(set.getString("spwd"));
}
//6 关闭连接 释放资源
JdbcUtil.close(set, sta, con);
return stu;
}
public static void addAllPreparedStatement(List<Student> list)throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//2 准备sql模板: 由占位符?替代所有的数据
String sql="insert into student(sname,sex,sage,score,sdy) values(?,?,?,?,?)";
//3 获取预编译对象:并关联sql模板
PreparedStatement sta=con.prepareStatement(sql);
for(Student stu:list){
//4 给占位符赋值
sta.setString(1, stu.getSname());//参数1:占位符的索引 从1开始 参数2:具体数据
sta.setString(2, stu.getSex());
sta.setInt(3, stu.getSage());
sta.setFloat(4, stu.getScore());
sta.setBoolean(5, stu.getSdy());
//5 执行execute方法
int hang=sta.executeUpdate();
System.out.println("添加"+hang+"行成功!");
}
//6 关闭连接 释放资源
JdbcUtil.close(null, sta, con);
}
public static void addAllStatement(List<Student> list)throws Exception{
// 1获取连接
Connection con=JdbcUtil.getCon();
//6 获取sql语句发射器对象
Statement sta=con.createStatement();
for(Student stu:list){
String sql="insert into student(sname,sex,sage,sdy,score) "
+ "values('"+stu.getSname()+"','"+stu.getSex()+"',"
+stu.getSage()+","+stu.getSdy()+","+stu.getScore()+")";
System.out.println(sql);
//7 执行execute方法 获取结果集
int hang=sta.executeUpdate(sql);
System.out.println("插入"+hang+"行成功!");
}
//6 关闭连接 释放资源
JdbcUtil.close(null, sta, con);
}
5 连接池
数据库连接池的基本原理就是为数据库建立一个缓冲池。在缓冲池中先创建指定数量的数据库连接,当有连接请求时就从缓冲池中取出处于“空闲”状态的连接,并将此连接标记为“忙碌”,直到该请求进程结束后,它所使用的连接才会重新回到“空闲”状态,并等待下一次请求调用。
数据库连接池的主要作用就是负责创建、分配、管理、维护和释放数据库连接,它允许程序重复使用同一个现有的数据库连接,大大缩短了运行时间,提高了执行效率
常见的数据库连接池
- c3p0
- dbcp
- druid:德鲁伊
使用步骤
1 导入jar
2 准备配置文件
3 创建获取连接的工具类
c3p0使用
-
1 导入c3p0依赖的jar
-
2 创建c3p0的配置文件:文件名字:c3p0-config.xml 文件位置:src
<?xml version="1.0" encoding="UTF-8"?> <!-- 声明区:当前xml页面属性 -->
<c3p0-config>
<default-config>
<!--mysql数据库连接的各项参数-->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db_11</property>
<property name="user">root</property>
<property name="password">root</property>
<!--配置数据库连接池的初始连接数、最小链接数、获取连接数、最大连接数、最大空闲时间-->
<property name="initialPoolSize">10</property>
<property name="minPoolSize">10</property>
<property name="acquireIncrement">5</property>
<property name="maxPoolSize">100</property>
<property name="maxIdleTime">30</property>
</default-config>
</c3p0-config>
- 3 创建c3p0的工具类
package com.zhiyou100.util;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3p0Util {
//静态属性获取连接池对象
private static DataSource ds=new ComboPooledDataSource();
//获取连接
public static Connection getCon(){
try {
return ds.getConnection();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//归还连接:通过DataSource获取的Connection对象的close方法已经被重写:不再是关闭连接 而是把连接归还给连接池
public static void release(ResultSet set,Statement sta,Connection con){
if(set!=null){
try {
set.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if(sta!=null){
try {
sta.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if(con!=null){
try {
con.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
System.out.println(getCon());
}
}