前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDBC干货二

JDBC干货二

作者头像
爱撒谎的男孩
发布2019-12-31 14:47:17
4120
发布2019-12-31 14:47:17
举报
文章被收录于专栏:码猿技术专栏码猿技术专栏

文章目录

  1. 1. Day02
    1. 1.1. Properties属性配置对象
      1. 1.1.1. 什么是properties
      2. 1.1.2. 把数据库中的信息存放到该文件中
      3. 1.1.3. 为什么要保存到该配置文件中
      4. 1.1.4. 存放数据
      5. 1.1.5. 存放数据注意事项
      6. 1.1.6. 读取Properties配置文件中的信息
    2. 1.2. 定义此时的工具类
    3. 1.3. 数据库连接池
      1. 1.3.1. 什么是数据库连接池(DBCP DatabaseConnection Pool)
      2. 1.3.2. 为什么用
      3. 1.3.3. 原理
      4. 1.3.4. 如何使用数据库连接池
    4. 1.4. JDBC工具类终极版
      1. 1.4.1. jdbc.properties(key-value 键值对形式存储)
      2. 1.4.2. 实现
      3. 1.4.3. 测试连接
      4. 1.4.4. 测试等待
    5. 1.5. PrepareStatement
      1. 1.5.1. 好处
      2. 1.5.2. sql注入

Day02

Properties属性配置对象

什么是properties

  • 程序猿可以把工程中出现的某些数据以配置文件的形式保存起来,就是处理 *.properties文件的对象,在properties文件中是以键值对形式保存的数据

把数据库中的信息存放到该文件中

  • 其中存放的是driver ,url , username,password

为什么要保存到该配置文件中

  • 因为以后的工作中有更换数据库的需求,此时如果写在java类中修改比较麻烦,所以需要把这些数据保存到配置文件中

存放数据

  • 在src的目录下创建一个jdbc.properties配置文件
  • 将数据库的信息保存到其中(键值对的形式)
代码语言:javascript
复制
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=root

存放数据注意事项

  • 数据是以键值的形式存放的(key-value)
  • value的值不能带有引号,并且后面不能有空格

读取Properties配置文件中的信息

  • 既然我们将数据库中的配置信息存放到配置文件中,我们当然需要将其读取到java代码中使用
  • 前提:这个配置文件在src目录下
代码语言:javascript
复制
@Test
public void testPro(){
	Properties properties=new Properties();  //创建Properties对象
	//使用类加载器生成输入流(读取)  前提是该配置文件必须在src目录下
	InputStream ips=TestProperties.class.getClassLoader().getResourceAsStream("jdbc.properties");
	try {
		properties.load(ips);
		String s1=properties.getProperty("url");   //直接读取,以键值
		System.out.println(s1);
	} catch (IOException e) {
		e.printStackTrace();
	}
}

定义此时的工具类

  • 我们引用了配置文件,那么我们的工具类就需要改变了,在工具类需要读取配置文件中数据库信息
  • 我们知道数据库的配置信息是不变的,因此我们不需要每次连接都加载一次,所以我们可以将读取数据库配置信息的代码放在静态语句块中,那么只有当类加载的时候才会加载一次
代码语言:javascript
复制

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * 数据库封装类
 * @author chenjiabing
 */
public class DBUtils {
	private static String driver;   //驱动
	private static String url;  //url
	private static String username;  //用户名
	private static String password;  //密码

	//静态语句块,只在使用类加载的时候加载一次,因为其中的数据不用每次都加载,所以只需要加载一次
	static{
		Properties properties=new Properties();  //创建对象
		//使用类加载器读取文件输入流
		InputStream ips=DBUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
		try {
			properties.load(ips);
			//读取属性值
			driver=properties.getProperty("driver");
			url=properties.getProperty("url");
			username=properties.getProperty("username");
			password=properties.getProperty("password");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	/**
	 * 获取连接对象
	 * @param user  数据库用户名
	 * @param password 密码
	 * @param database : 数据库名称
	 */
	public static Connection getConnection() throws Exception {
		Class.forName("com.mysql.jdbc.Driver"); // 注册驱动
		// 链接数据库
		Connection connection = DriverManager.getConnection(
				url, username, password);
		return connection;
	}

	/**
	 * 关闭数据库资源
	 * @param connection 连接对象
	 * @param statement Statement对象
	 * @param resultSet 结果集
	 */
	public static void close(Connection connection, Statement statement,
			ResultSet resultSet) {
		try {
			if (resultSet != null) {
				resultSet.close();
			}

			if (statement != null) {
				statement.close();
			}

			if (connection != null) {
				connection.close();
			}
		} catch (Exception exception) {
			exception.printStackTrace();
		}

	}

}

数据库连接池

什么是数据库连接池(DBCP DatabaseConnection Pool)

  • 一套管理数据库连接的api

为什么用

  • 如果没有数据库连接池的话,每次和数据库进行交互都需要建立连接和关闭连接,如果有1万次交互就有一万次建立和关闭连接,频繁开关连接非常消耗资源。使用数据库连接池,可以设置一个初始连接数量,如果有连接需求会和连接池要,连接池中有空闲连接则用空闲的,如果没有此时会检测是否是最大数量,如果是则等待,如果不是则创建新的连接,每个连接使用完之后会归还到连接池中。等待连接池的,如果有归还的连接会直接得到此连接进行操作

原理

  • 使用数据库连接池,可以设置一个初始连接数量,如果有连接需求会和连接池要,连接池中有空闲连接则用空闲的,如果没有此时会检测是否是最大数量,如果是则等待,如果不是则创建新的连接,每个连接使用完之后会归还到连接池中。等待连接池的,如果有归还的连接会直接得到此

如何使用数据库连接池

  1. 下载jar包
    • 去maven私服中,找到dbcp-1.4版本的
    • 添加依赖 <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency>
  2. 初次使用(连接数据库)
代码语言:javascript
复制
//创建数据源对象
		BasicDataSource dataSource=new BasicDataSource();

		//设置连接信息  driver url username password
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://localhost:3306/jdbc");
		dataSource.setUsername("root");
		dataSource.setPassword("root");

		//设置连接池策略信息
		dataSource.setInitialSize(3);  //设置初始连接数量
		dataSource.setMaxActive(5);  //设置最大连接数量

		//获取连接
		Connection connection=dataSource.getConnection();

		System.out.println(connection);

JDBC工具类终极版

  • 使用数据库连接池
  • 使用了properties配置文件的形式存储数据库配置信息

jdbc.properties(key-value 键值对形式存储)

  • value最后不能有空格
  • value的值不能用引号
  • 因为使用的是类加载器加载的,因此这个文件的位置应该在src目录下
代码语言:javascript
复制
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=root
initSize=3
maxSize=5

实现

  • 数据库的配置信息不是经常改变的,因此不用每次使用都重新加载,只需要加载一次(静态语句块)
  • 数据源和数据库连接池的配置信息(初始连接数量,最大连接数量) 只需要加载一次(静态语句块)
代码语言:javascript
复制

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import org.apache.commons.dbcp.BasicDataSource;

/**
 * 数据库封装类 : 终极版
 * @author chenjiabing
 */
public class DBUtils {
	private static String driver;   //驱动
	private static String url;  //url
	private static String username;  //用户名
	private static String password;  //密码
	private static String maxSize;  //最大连接数量
	private static String initSize;  //初始化连接数量
	private static BasicDataSource dataSource;  //数据源


	//静态语句块,只在使用类加载的时候加载一次,因为其中的数据是不会经常改变的,所以只需要加载一次
	static{
		Properties properties=new Properties();  //创建对象
		//使用类加载器读取文件输入流
		InputStream ips=DBUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
		try {
			properties.load(ips);
			//读取属性值
			driver=properties.getProperty("driver");
			url=properties.getProperty("url");
			username=properties.getProperty("username");
			password=properties.getProperty("password");
			initSize=properties.getProperty("initSize");
			maxSize=properties.getProperty("maxSize");

			dataSource=new BasicDataSource();   //获取数据源
			//设置数据源的属性-----数据库的配置信息
			dataSource.setDriverClassName(driver);
			dataSource.setUrl(url);
			dataSource.setUsername(username);
			dataSource.setPassword(password);
			dataSource.setInitialSize(Integer.parseInt(initSize));
			dataSource.setMaxActive(Integer.parseInt(maxSize));

		} catch (IOException e) {
			System.out.println("配置文件jdbc.properties读取失败!!!");
			e.printStackTrace();
		}
	}

	/**
	 * 获取数据库连接
	 * @return
	 * @throws Exception
	 */
	public static Connection getConnection() throws Exception {
		Connection connection=dataSource.getConnection();
		return connection;
	}

	/**
	 * 关闭数据库资源
	 * @param connection 连接对象
	 * @param statement Statement对象
	 * @param resultSet 结果集
	 */
	public static void close(Connection connection, Statement statement,
			ResultSet resultSet) {
		try {
			if (resultSet != null) {
				resultSet.close();
			}

			if (statement != null) {
				statement.close();
			}

			if (connection != null) {
				connection.close();
			}
		} catch (Exception exception) {
			exception.printStackTrace();
		}

	}

}

测试连接

代码语言:javascript
复制
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Test;
import com.jsnu.db.DBUtils;

public class TestDBUtils {
	@Test
	public void test() {
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			connection = DBUtils.getConnection();  //获取连接

			statement = connection.createStatement();  //创建Statement语句对象

			String select_sql = "select * from t";

			resultSet = statement.executeQuery(select_sql);  //执行查询方法

			while (resultSet.next()) {
				int id = resultSet.getInt("id");   //获取属性
				String name = resultSet.getString("name");
				int age = resultSet.getInt("age");
				System.out.println(id + "---" + age + " ----" + name);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.close(connection, statement, resultSet);  //关闭资源
		}

	}
}

测试等待

  • 我们知道连接池有最大的连接限制,只要连接的数量需求超过最大值,那么我们就需要等待,直到连接池中有空闲的连接。
  • 上面我们设置的最大连接数量为5,此时我们利用多线程来测试等待的过程
  • connection.close 就是归还连接,因为连接关闭了
  • 线程类:
代码语言:javascript
复制
public class TestDButils2 extends Thread {
	@Override
	public void run() {
		try {
			Connection connection=DBUtils.getConnection();
			System.out.println(connection);  //获取连接
			System.out.println(this.getName()+ ": 正在运行");
			Thread.sleep(5000);   //睡眠5s
			connection.close();  //关闭连接,相当于释放连接,归还到连接池中
			System.out.println(this.getName()+":连接已经归还");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
  • main方法中测试
    • 在main方法中创建了六个线程,那么最大的连接数量是5,此时肯定有一个线程在等待获取连接,直到前面的线程归还连接才会执行
代码语言:javascript
复制

public static void main(String[] args) {
		for(int i=0;i<=6;i++){
			TestDButils2 testDButils2=new TestDButils2();
			testDButils2.start();   //线程启动
		}
	}

PrepareStatement

好处

  • 代码结构更加清晰,比拼接字符串出错概率要低
  • 执行效率要比Statement高(效果不是太明显)因为使Statement每次执行sql都需要把sql编译成执行计划,而PrepareStatement只需要创建时转化一次,之后只需要修改里面的值即可,所以效率会高
  • 有预编译可避免sql注入,预编译的时候把sql语句的逻辑已经定死,不能再向其中添加新的逻辑

sql注入

  • 创建用户表
    • drop table user if exists; //有则先删除
    • create table user(id int primary key auto_increment,username varchar(10),password varchar(20));
    • insert into user(username,password) values(‘libai’,’admin’),(‘zhaosi’,’123456’);
  • 用户登录
    • 根据用户名和密码查询人数,如果 >0 表示有这个人,如果 <0 登录失败
    • select count(*) from user where username=”libai” and password=”admin”;
    • 我们只需要使用select count(*) from user where username='xds' and password='' or '1'='1' 那么会直接登录成功,无论用户名和密码是多少。这种是使用Statement才会生效,因为其中的sql是拼接的。我们只需要输入密码为 ' or '1'=1即可sql注入
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-03-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Day02
    • Properties属性配置对象
      • 什么是properties
      • 把数据库中的信息存放到该文件中
      • 为什么要保存到该配置文件中
      • 存放数据
      • 存放数据注意事项
      • 读取Properties配置文件中的信息
    • 定义此时的工具类
      • 数据库连接池
        • 什么是数据库连接池(DBCP DatabaseConnection Pool)
        • 为什么用
        • 原理
        • 如何使用数据库连接池
      • JDBC工具类终极版
        • jdbc.properties(key-value 键值对形式存储)
        • 实现
        • 测试连接
        • 测试等待
      • PrepareStatement
        • 好处
        • sql注入
    相关产品与服务
    数据库
    云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档