JDBC基础知识

1 概念

jdbc:java database conncetion
      通过java程序来连接数据库
      sun公司定义的通过java连接所有数据库的一组接口(标准)
jdbc驱动: 不同数据库产品 底层的实现原理/操作不同
          不同数据库的厂商 为自己的数据库提供的jdbc的实现类

2 案例

创建web项目

image
image
image

创建测试类

测试插入一行记录

        //通过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使用

<?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());
	 }
}
posted @ 2021-09-29 16:03  RenVei  阅读(66)  评论(0编辑  收藏  举报