import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQLInject2 {
public static void main(String[] args) throws Exception {
read2(“‘or 1 or’”);// 会查询表里面的全部内容
// 利用MySQL的一些关键字产生错误
}
public static void read2(String name) throws Exception {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String url = “jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC”;
// url格式:jdbc:自协议:子名称//主机名:端口/数据库名称
String userName = “root”;
String password = “mysql”;
try {
// 1.注册驱动
Class.forName(“com.mysql.jdbc.Driver”);
// 2.建立连接
conn = DriverManager.getConnection(url, userName, password);
// 3.创建语句
// PreparedStatement可以对sql语句进行预处理,过滤一些MySQL中的字符
String sql = “select * from user where name=?”;
ps = conn.prepareStatement(sql);
ps.setString(1, name);
// 4.执行语句
rs = ps.executeQuery();
// 5.处理结果
while (rs.next()) {// 按行遍历
System.out.println(rs.getObject(“id”) + “\t” + rs.getObject(“name”)
-
“\t” + rs.getObject(“birthday”)
-
“\t” + rs.getObject(“money”) + “\t”);// 获取每一列
}
} finally {
// 6.释放资源(后创建的先关闭):调用工具类中的方法
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
}
三、使用工具类编写JDBC程序
===============
在使用JDBC连接数据库的过程中,我们发现大多数步骤都是一样的,如第(1)、(2)步注册驱动、建立连接,以及第(6)步释放资源的代码完全以封装起来。而我们平常使用数据库的频率如果很高所以我们需要对JDBC的通用代码进行提炼,提高代码复用率,提炼出来的工具类我们一般称为JDBCUtils,工具类中包含了我们常用的很多方法,比如连接数据库和断开连接就是常用的方法,我们只要掌握了JDBC原理,就可以自己设计满足需求工具类或参考以下工具类(后面我们会说到DBUtils工具类,这是Apache组织提供的JDBC工具类,比较全面,基本能够满足我们的需求)
如下为将第(1)、(2)步注册驱动、建立连接,以及第(6)步释放资源的代码封装进工具类的代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcUtils {
private static String url=“jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC”;//url格式:jdbc:自协议:子名称//主机名:端口/数据库名称
private static String name=“root”;
private static String password=“mysql”;
private JdbcUtils() {
}
//1.注册驱动
static {
try {
Class.forName(“com.mysql.jdbc.Driver”);
}catch(ClassNotFoundException e) {
throw new ExceptionInInitializerError(e);
}
}
//2.建立连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,name,password);
}
// 6.释放资源(后创建的先关闭)
public static void free(ResultSet rs, Statement st,Connection conn) {
try{
if(rs!=null)
rs.close();
}catch(SQLException e) {
e.printStackTrace();
}finally {
try{
if(st!=null)
st.close();
}catch(SQLException e) {
e.printStackTrace();
}finally {
try{
if(conn!=null)
conn.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
}
}
}
2.4中的代码就可以通过工具类JdbcUtils中的静态代码块实现注册驱动,通过getConnection()静态方法实现与数据库建立连接,通过free()方法实现资源的释放。
调用工具类的代码如下:
public static void read2(String name) throws Exception {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
//1.注册驱动:工具类实现
//2.建立连接:调用工具类中的方法
conn=JdbcUtils.getConnection();
//3.创建语句并建立语句执行对象
/*
-
PreparedStatement相比于Statement的优势:
-
1、PreparedStatement没有SQL注入的问题,可以对sql语句进行预处理,过滤一些MySQL中的字符
-
2、当需要执行多次相似的SQL命令时,能够比较高效地执行。(只执行一次的话,PreparedStatement会包含与处理的时间)
*/
String sql=“select * from user where name=?”;
ps=conn.prepareStatement(sql);
ps.setString(1, name);
//4.执行语句
rs=ps.executeQuery();//区别于Statement,不传入参数
//5.处理结果
while(rs.next()) {//按行遍历
System.out.println(rs.getObject(“id”)+“\t”+rs.getObject(“name”)+“\t”
+rs.getObject(“birthday”)+“\t”+rs.getObject(“money”)+“\t”);//获取每一列
}
}finally {
//6.释放资源(后创建的先关闭):调用工具类中的方法
JdbcUtils.free(rs, ps, conn);
}
}
}
四、连接池的使用
========
4.1、连接池是什么?为什么使用连接池?
程序开发过程中,存在很多问题:首先,每一次web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。
上述问题的根源就在于对数据库连接资源的低效管理。我们知道,对于共享资源,有一个很著名的设计模式:资源池(resource pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。
4.2、自定义共享连接池
Java提供了一个公共接口:Javax.sql.DataSource。此接口提供了 DataSource
对象所表示的物理数据源的连接。作为 DriverManager
工具的替代项,DataSource
对象是获取连接的首选方法。
简单来说,就是DateSource接口是Drivermanager的替代项,提供了getConnection()方法并生产标准的Connection对象,那么要实现连接池,就需要实现该接口和该方法。
一般步骤:
-
实现数据源DataSource,即实现Javax.sql.DataSource接口;由于只是简单的演示,我们只实现其中的getConnection()和returnConnToPool()方法即可。使用getConnection()取出连接对象,使用returnConnToPool()归还连接对象。
-
创建一个LinkList容器。既然是“池子”,就需要保存东西,即存储连接池对象,而连接池涉及移除/添加连接池对象,优先考虑使用LinkList来存储。
-
使用静态代码块初始化若干个连接池对象。由于只是测试,我们初始化5个就行。
-
实现getConnection()方法。注意,为了保证连接对象只提供给一个线程(一个用户)使用,我们需要先将连接对象从池子中取出来。
-
用完的连接对象不需要执行close()而是放回池子去。
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;
import javax.sql.DataSource;
import cn.itcast.jdbc.JdbcUtils;
public class MyDataSource implements DataSource {// [1]实现接口
// [2]创建一个容器存储连接池里的Connection对象。
private static LinkedList pool = new LinkedList();
// [3]初始化3个Connection对象放进池子。
static {
Connection conn = null;
for (int i = 0; i < 3; i++) {
try {
conn = JdbcUtils.getConnection();
} catch (SQLException e) {
e.printStackTrace();
} // 这里我们使用上面创建的JdbcUtils来获取连接
pool.add(conn);
}
}
@Override
// [4]从池子里取连接对象
public Connection getConnection() throws SQLException {
// 使用前先判断连接池是否有连接对象,没有则添加
Connection conn = null;
if (pool.size() == 0) {
for (int i = 0; i < 5; i++) {
conn = JdbcUtils.getConnection();
pool.add(conn);
}
}
conn = pool.removeFirst();// 取出来
return conn;
}
// [5]用完归还连接到连接池
public boolean returnConnToPool(Connection conn) {
return pool.add(conn);
}
// 下面是未实现的方法。
@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 unwrap(Class 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;
}
}
上面通过自定义连接池的案例简单介绍了连接池的原理。事实上,我们在开发过程中,不需要再关心数据库连接的问题,因为实际开发过程中有成熟的数据库连接池帮助我们处理。下面为大家介绍c3p0和DBCP连接池的使用,笔者通过案例介绍这两个连接池的简单实用,更为深层次的理解和使用大家可以参照他们各自的API。
(1)c3p0的API:https://www.mchange.com/projects/c3p0/
(2)DBCP的API:http://commons.apache.org/proper/commons-dbcp/apidocs/index.html
4.3、c3p0连接池
使用c3p0需要都jar包:c3p0-0.9.1.2.jar
使用方式一:快速创建
该方法对应于c3p0的API中快速创建部分,需要在程序内通过ComboPooledDataSource类的对象设置数据库的url地址、用户名user和用户密码password等信息。最后通过ComboPooledDataSource类的对象调用getConnection()方法获取连接池中的连接。
@Test
public void testC3p0() throws Exception {
/**
-
查看c3p0的API:网址:https://www.mchange.com/projects/c3p0/
-
- 如何快速创建
-
- 如何使用xml文件
-
此部分代码对应为API中的为快速创建c3p0
*/
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( “com.mysql.jdbc.Driver” ); //loads the jdbc driver
cpds.setJdbcUrl( “jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC” );
cpds.setUser(“root”);
cpds.setPassword(“mysql”);
Connection conn=cpds.getConnection();
System.out.println(conn);
}
使用方式二:使用xml文件
此部分内容参考于c3p0的API中 Appendix B: Configuation Files 的内容
步骤为:
1. 创建 c3p0-config.xml 文件,
参考帮助文档中 Appendix B: Configuation Files 的内容
- 创建 ComboPooledDataSource 实例;
DataSource dataSource =
new ComboPooledDataSource(“helloc3p0”);
- 从 DataSource 实例中获取数据库连接.
配置文件 c3p0-config.xml的代码如下:需要注意的是,配置时诸如"driverClass"、“jdbcUrl”、"initialPoolSize"等属性名需和API当中要求的一致,否则无法识别。
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC
root
mysql
50
5
5
10
20
5
通过c3p0-config.xml 文件使用c3p0连接池的代码为:
@Test
public void testC3poWithConfigFile() throws Exception{
/**
-
查看c3p0的API:网址:https://www.mchange.com/projects/c3p0/
-
- 如何快速创建
-
- 如何使用xml文件
-
此部分代码为使用xml文件实现c3p0
*/
/**
-
- 创建 c3p0-config.xml 文件,
-
参考帮助文档中 Appendix B: Configuation Files 的内容
-
- 创建 ComboPooledDataSource 实例;
-
DataSource dataSource =
-
new ComboPooledDataSource("helloc3p0");
-
- 从 DataSource 实例中获取数据库连接.
*/
DataSource dataSource =
new ComboPooledDataSource(“helloc3p0”); //helloc3p0是c3p0-config.xml文件的名称
Connection conn=dataSource.getConnection();
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后总结我的面试经验
2021年的金三银四一眨眼就到了,对于很多人来说是跳槽的好机会,大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。
另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
BAT面试经验
实战系列:Spring全家桶+Redis等
其他相关的电子书:源码+调优
面试真题:
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!**
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后总结我的面试经验
2021年的金三银四一眨眼就到了,对于很多人来说是跳槽的好机会,大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。
另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
[外链图片转存中…(img-eTcptr38-1713684704674)]
BAT面试经验
实战系列:Spring全家桶+Redis等
[外链图片转存中…(img-WyYHKN7j-1713684704674)]
其他相关的电子书:源码+调优
[外链图片转存中…(img-b8kyHeNY-1713684704674)]
面试真题:
[外链图片转存中…(img-il61QADW-1713684704675)]
[外链图片转存中…(img-W8KxECUA-1713684704675)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!