web day06(jdbc)

JDBC概述
在这里插入图片描述
驱动
为了能让程序员利用java程序操作数据库,数据库厂商提供了一套jar包,通过导入这个jar包,就可以直接调用里边的方法操作数据库,这个jar包称之为驱动
两个数据库驱动互不兼容:
行业中有很多种数据库,要使用这么多数据库需要学习很多的数据库驱动,对于程序员来说学习成本非常高;想让java程序兼容数据库,所有的数据库驱动都实现了jdbc这套接口
JDBC简介
JDBC全称:java Data Base Connectivity(java数据库连接),它主要由接口组成
组成jdbc的两个包:java.sql javax.sql包
开发jdbc应用需要以上两个包的支持外,还需要导入相应的jdbc的数据库实现驱动
不仅需要jdbc接口,还需要驱动这个实现,驱动就是对jdbc的接口的一些实现
ctrl shift o ------导包

public class Demo1 {
	public static void main(String[] args) throws SQLException {
		//获取数据库驱动
		DriverManager.registerDriver(new Driver());
		//创建数据库连接
		Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "root");
		//获取传输器
		Statement stat=conn.createStatement();
		//利用传输器传输sql,并获取返回结果
		ResultSet rs=stat.executeQuery("select * from emp");
		//遍历结果
		while(rs.next()) {
			int id=rs.getInt("id");
			String name=rs.getString(2);
			System.out.println("id:"+id+">>"+"name:"+name);
		}
		//关闭资源
		//后创建的先关闭
		rs.close();
		stat.close();
		conn.close();
	}
}
public class Demo2 {
	public static void main(String[] args){
		Connection conn=null;
		Statement stat=null;
		ResultSet rs=null;
		try {
			//获取数据库驱动
			//手动注册一次,底层还注册一次,总共两次注册驱动,应该只注册一次即可
			//代码与mysql驱动包包名绑死,如果切换数据则需要修改包名代码
			//DriverManager.registerDriver(new Driver());
			Class.forName("com.mysql.jdbc.Driver");
			//创建数据库连接
			//Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "root");
			conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?user=root&password=root");
			//获取传输器
			stat=conn.createStatement();
			//利用传输器传输sql,并获取返回结果
			rs=stat.executeQuery("select * from emp");
			//遍历结果
			while(rs.next()) {
				int id=rs.getInt("id");
				String name=rs.getString(2);
				System.out.println("id:"+id+">>"+"name:"+name);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}finally {
			//关闭资源
			//后创建的先关闭
			if(rs!=null) {
				try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}finally {
				rs=null;
			}
			}
			if(stat!=null) {
				try {
				stat.close();
			} catch (SQLException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}finally {
				stat=null;
			}
			}
			if(conn!=null) {
				try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}finally {
				conn=null;
			}
		}
			}
			
		}
		
		
}
public class Demo3 {
	//添加数据库的sql
	@Test
	public void add() {
		Connection conn=null;
		Statement stat=null;
		try {
			//注册数据库驱动
			Class.forName("com.mysql.jdbc.Driver");
			//创建数据库连接
			conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "root");
			//获取传输器
			stat=conn.createStatement();
			//利用传输器传输sql
			int count=stat.executeUpdate("insert into emp values(null,'曹阳',7)");
			if(count>0) {
				System.out.println("插入成功,受到影响的行数为:"+count);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}finally {
			if(conn!=null) {
				try {
					conn.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					conn=null;
				}
			}
			if(stat!=null) {
				try {
					stat.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					stat=null;
				}
			}
		}
		
	}
	//修改信息的sql
	@Test
	public void update() {
		Connection conn=null;
		Statement stat=null;
		try {
			//注册驱动,创建连接
			conn=JDBCUtils.getConnection();
			//获取传输器
			stat=conn.createStatement();
			//删除
			int count=stat.executeUpdate("update emp set name='李帅' where id=7");
			if(count>0) {
				System.out.println("更新成功,"+"受影响的行数为:"+count);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}finally {
			//关闭资源
			JDBCUtils.close(conn, stat, null);
		}
		
	}
	//删除sql
	@Test
	public void delete() {
		Connection conn=null;
		Statement stat=null;
		try {
			//注册驱动,创建连接
			conn=JDBCUtils.getConnection();
			//获取传输器
			stat=conn.createStatement();
			//删除操作
			int count=stat.executeUpdate("delete from emp where id=8");
			if(count>0) {
				System.out.println("删除成功,"+"受影响的行数为:"+count);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}finally {
			//关闭资源
			JDBCUtils.close(conn, stat, null);
		}
	}
}

登录功能的实现:

public class Login {
	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();
		//testLogin(username,password);
		preparedTestLogin(username,password);
	}

	private static void preparedTestLogin(String username, String password) {
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		try {
			conn=JDBCUtils.getConnection();
			//发送sql主干
			ps=conn.prepareStatement("select * from user where name=? and password=?");
			//发送参数
			ps.setString(1, username);
			ps.setString(2, password);
			//通知数据库服务器执行sql
			rs=ps.executeQuery();
			if(rs.next()) {
				System.out.println("登录成功");
			}else {
				System.out.println("登录失败");
			}
		} catch (Exception e) {
			// TODO: handle exception
		}finally {
			//关闭资源
			JDBCUtils.close(conn, ps, rs);
		}
	}

	private static void testLogin(String username, String password) {
		Connection conn=null;
		Statement stat=null;
		ResultSet rs=null;
		try {
			conn=JDBCUtils.getConnection();
			stat=conn.createStatement();
			rs=stat.executeQuery("select * from user where name='"+username+"' and password='"+password+"'");
			if(rs.next()) {//若果为true证明能查询到用户名和密码,可以登录(name为曹阳'#,password为空也是成功的,sql注入攻击)
				System.out.println("登录成功");
			}else {
				System.out.println("登录失败...");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//关闭资源
			JDBCUtils.close(conn, stat, rs);
		}
	}
}

sql注入攻击
由于sql语句是由前台参数与后台语句拼接而来,在用户传入参数位置可能会输入数据库的关键字。这些关键字可能使得sql语句的语义发生变化,从而达到一些特殊的效果,这种操作方式称之为sql注入攻击
解决方案:
1.利用statement子接口preparedStatement可以有效防止sql注入攻击
PreparedStatement概述:
preparedStatement是statement的一个子接口
具有预编译功能
发送sql的步骤:
1.先将sql语句的主干部分发送到数据库服务器中,sql语句到达服务器中时,会立即变成一段机器码(二进制数据)这个机器码不能被操作
2.再将sql语句中的参数发送到数据库服务器,这些参数到达数据库中时只会作为纯文本内容使用
preparedStatement的优势:
参数可以单独传入,避免sql语句的拼接错误。
拥有预编译功能,可以防止sql注入攻击

javautils工具包

public class JDBCUtils {
	private JDBCUtils() {}
	//静态对象
	public static Properties prop=new Properties();
	static{
				//获取类加载器JDBCUtils.class.getClassLoader()
				//通过类加载器获取src目录,getResource()
				//getResource()会得到从盘符到src目录的路径
				//直接在括号中书写文件名称即可得到文件路径
				//getPath()可将url数据转为String类型的数据
				try {
					prop.load(new FileInputStream(new File(JDBCUtils.class.getClassLoader().getResource("conf.properties").getPath())));
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
					throw new RuntimeException();
				}
	}
	//创建连接
	public static Connection  getConnection() throws Exception {
		//注册数据库驱动
		Class.forName(prop.getProperty("driver"));
		//Class.forName("com.mysql.jdbc.Driver");
		//创建数据库连接
		return DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("user"), prop.getProperty("password"));
		//return DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "root");
		}
		//关闭资源
		public static void close(Connection conn,Statement stat,ResultSet rs) {
			if(conn!=null) {
				try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException();
			}finally {
				conn=null;
			}
		}
			if(stat!=null) {
				try {
					stat.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					stat=null;
				}
			}
			if(rs!=null) {
				try {
					rs.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					rs=null;
				}
			}
			
			}
			
}

conf.properties
在这里插入图片描述

在这里插入图片描述

批处理:
1.批处理机制
a.在sql语句的执行过程中,每个jdbc六部分只操作一个语句,如果有多个sql要执行,会造成很大的代码冗余,书写不便利。
b.可以将这些sql语句放入一个jdbc的批处理中,一同发送给数据库服务器执行

statement批处理和preparedStatement批处理
a.statement批处理

package cn.tedu.batch;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import cn.tedu.utils.JDBCUtils;
//批处理statement
/*  
create table t1(id int,name varchar(20))
insert into t1 values(1,'鸣人')
insert into t1 values(2,'佐助')
insert into t1 values(3,'小音')
insert into t1 values(1,'鞋')
 * */
public class StateBatchDemo1 {
	public static void main(String[] args) {
		Connection conn=null;
		Statement stat=null;
		ResultSet rs=null;
		try {
			conn=JDBCUtils.getConnection();
			stat=conn.createStatement();
			//添加sql到批处理中
			stat.addBatch("create table t1(id int,name varchar(20))");
			stat.addBatch("insert into t1 values(1,'鸣人')");
			stat.addBatch("insert into t1 values(2,'佐助')");
			stat.addBatch("insert into t1 values(3,'小音')");
			stat.addBatch("insert into t1 values(4,'鞋')");
			//通知数据库服务器执行批处理
			stat.executeBatch();
			System.out.println("Statement批处理执行成功");
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.close(conn, stat, rs);
		}
	}
	
}

preparedstatement批处理:

package cn.tedu.batch;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import cn.tedu.utils.JDBCUtils;

/**
*@author 作者:
*@version 创建时间:2021年1月13日下午1:38:32
*@description 描述:批处理preparestatement
*/
public class PreparedBatchDemo1 {
	public static void main(String[] args) {
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		try {
			conn=JDBCUtils.getConnection();
			ps=conn.prepareStatement("insert into t1 values(?,?)");
			for (int i = 0; i < 10000; i++) {
				//添加sql参数到批处理中
				ps.setInt(1, i);
				ps.setString(2, "name"+i);
				ps.addBatch();
				if(i%1000==0) {
					//执行批处理
					ps.executeBatch();
					//清空批处理
					ps.clearBatch();
					System.out.println("执行完毕,当前批次数为:"+i/1000);
				}
			}
			//循环可能有不满一千的数据,通过本句来执行
			ps.executeBatch();
			System.out.println("preparestatement执行完毕");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.close(conn, ps, rs);
		}
	}
}

preparestatement的特点:
优点:
1.具有预编译功能
2.将sql主干预留在数据库服务器中,不必重复发送sql语句
3.每次仅发送sql的参数部分,执行效率较高
缺点:
1.只能执行同一语义的sql语句

statement特点:
优点:
1.可以执行不同语义的sql
缺点:
1.没有预编译功能
2.每次都会将完整的sql语句发送到数据库服务器中
3.无法预留sql语句在服务器中,执行效率较低

连接池:
为什么创建连接池:
在这里插入图片描述
一般数据库连接缺点:
用户每次请求都要向数据库获取连接,而数据库创建连接一般需要消耗相对较大的资源,创建时间也较长,假设网站一天需要创建10万次连接,极大的浪费数据库的资源,极易造成数据库服务器内存溢出,宕机

在这里插入图片描述
连接池的额实现:
在这里插入图片描述
连接池概念:
在使用JDBC的过程中,连接池的使用占用资源较少,而创建连接和销毁连接占用资源较多,为了减少在服务器和数据库服务器之间,创建连接和销毁连接的过程,可以使用的连接池代替原来的jdbc有关连接的操作
连接池原理:
连接池在服务器启动的时候,会自动向数据库服务器索要一批链接,这些连接会保留在连接池中,用户需要访问数据库时,可以从连接池中取出连接,使用完成后,可以归还连接,从而省去创建和销毁的过程

package cn.tedu.pool;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;

import javax.sql.DataSource;

/**
*@author 作者:
*@version 创建时间:2021年1月13日下午2:40:28
*@description 描述:连接池底层源码
*/
public class MyPool implements DataSource{
	//当前类加载时初始化一些连接
	public static LinkedList<Connection> pool=new LinkedList<Connection>();
	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");
			for (int i = 0; i <5; i++) {
				Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "root");
				pool.add(conn);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Override
	public Connection getConnection() throws SQLException {
		//获取连接
		if(pool.size()==0) {
			for (int i = 0; i <5; i++) {
				Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "root");
				pool.add(conn);
			}
		}
		Connection conn=pool.remove(0);
		System.out.println("从池中取出连接,池中还剩"+pool.size()+"个连接");
		return conn;
	}
	//归还连接
	public  void returnConnection(Connection conn) throws SQLException {
		if(conn!=null && !conn.isClosed()) {
			pool.add(conn);
			System.out.println("归还连接,池中还剩"+pool.size()+"个连接");
		}
	}
	@Override
	public PrintWriter getLogWriter() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setLogWriter(PrintWriter out) throws SQLException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setLoginTimeout(int seconds) throws SQLException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public int getLoginTimeout() throws SQLException {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Connection getConnection(String username, String password) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}
	
}

package cn.tedu.pool;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
*@author 作者:
*@version 创建时间:2021年1月13日下午2:59:31
*@description 描述:测试连接池
*/
public class TestPool {
	public static void main(String[] args) {
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		MyPool pool=new MyPool();
		try {
			conn=pool.getConnection();
			ps=conn.prepareStatement("select * from exam where id=?");
			ps.setInt(1, 1);
			rs=ps.executeQuery();
			while (rs.next()) {
				String name=rs.getString("name");
				System.out.println("name:>>"+name);
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(conn!=null) {
				try {
				pool.returnConnection(conn);
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException();
			}finally {
				conn=null;
			}
		}
			if(ps!=null) {
				try {
					ps.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					ps=null;
				}
			}
			if(rs!=null) {
				try {
					rs.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					rs=null;
				}
			}
			
			}
		}
	
}

DBCP的连接使用

package cn.tedu.pool;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

/**
*@author 作者:
*@version 创建时间:2021年1月13日下午3:13:11
*@description 描述:dbcp连接池测试使用
*/
public class DBCPDemo1 {
	public static void main(String[] args) {
		Connection conn=null;
		Statement stat=null;
		ResultSet rs=null;
		/*BasicDataSource source=new BasicDataSource();
		source.setDriverClassName("com.mysql.jdbc.Driver");
		source.setUrl("jdbc:mysql://localhost:3306/mydb");
		source.setUsername("root");
		source.setPassword("root");*/
		//利用工厂生产一个DBCP数据源对象
		Properties prop=new Properties();
	    try {
			prop.load(new FileInputStream(new File(DBCPDemo1.class.getClassLoader().getResource("dbcp.properties").getPath())));
			BasicDataSourceFactory factory=new BasicDataSourceFactory();
			DataSource source=factory.createDataSource(prop);
			conn=source.getConnection();
			stat=conn.createStatement();
			rs=stat.executeQuery("select * from exam");
			while (rs.next()) {
				int id=rs.getInt(1);
				String name=rs.getString(2);
				System.out.println("id:"+id+">>name"+name);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(conn!=null) {
				try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException();
			}finally {
				conn=null;
			}
		}
			if(stat!=null) {
				try {
					stat.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					stat=null;
				}
			}
			if(rs!=null) {
				try {
					rs.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					rs=null;
				}
			}
		}
		
	}
}

dbcp.properties配置
在这里插入图片描述
c3p0的测试使用

package cn.tedu.pool;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
*@author 作者:
*@version 创建时间:2021年1月13日下午3:50:32
*@description 描述:c3p0连接池测试使用
*/
public class C3P0Demo1 {
	public static void main(String[] args) {
		Connection conn=null;
		Statement stat=null;
		ResultSet rs=null;
		ComboPooledDataSource source=new ComboPooledDataSource();
		try {
			/*source.setDriverClass("com.mysql.jdbc.Driver");
			source.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
			source.setUser("root");
			source.setPassword("root");*/
			conn=source.getConnection();
			stat=conn.createStatement();
			rs=stat.executeQuery("select * from exam");
			while (rs.next()) {
				String name=rs.getString("name");
				System.out.println("name:>>"+name);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(conn!=null) {
				try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException();
			}finally {
				conn=null;
			}
		}
			if(stat!=null) {
				try {
					stat.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					stat=null;
				}
			}
			if(rs!=null) {
				try {
					//归还连接
					rs.close();
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				}finally {
					rs=null;
				}
			}
		}
	}
}

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值