JDBC连接数据库及其连接池

之所有要写这么一个数据库连接方法,就是为了有一个整理一下思路和所需要的东西总是会丢三落四,总是不好找,所以整理好,总不至于在需要的东西总是找不到。

一:JDBC连接数据库:

首先,连接数据库的准备工作:

1.我所用的编写工具为eclipse和Navicat。

2.连接数据库要有所需要的jar包。

自定义连接只需要jar包为驱动包Mysql—connector-java-xxx-bin.jar

在连接中所需要的类有Connection类、ResultSet类、Statement类。

那么究竟怎样才能连接到数据库,并且能在界面化上才做数据呢?要想完成这样的操作,首先我们要得和Navicat获取连接。我们要加载连接数据库的驱动。也就是上面所需要的jar包驱动,把它放在eclipse中新建的工程的lib里面,在build Path一下,使用Class.forName(“com.mysql.jdbc.Driver”)来注册驱动。这就完成了对驱动的注册,之后获取数据库的连接,使用Manager.getConnection(url,username,password),url="jdbc:mysql://127.0.0.1/3306/表名?useUnicoding=true&characterEncoding=utf8",username="连接数据库的名称",password="连接数据库的密码";这样就已经连接上了数据库。

那么接下来我们就对数据库进行操作:

我们知道,对数据库的操作‘无非就是对数据库的增删改查,我们写出相应的增删改查的sql语句。

增:insert into 表名(firstName,secondName,thirdName,fourthName) values(?,?,?,?);

删:delet frome 表的名称 where 条件;

改:updata 表名 set 字段="需要改的值" where ID="条件";

查:select * from 表名;查询所有的值;

写出相应的SQL语句,并且创建出Statement对象;connection.excuteQuery(sql);这样查询相应的数据。connction.executUpdate(sql);来执行相应的增删改;

使用Statement类我们需要注意一个问题,那就是会出现sql注入问题,所以一般我们会使用PrepareStatement类,所以在使用的时候,创建出所使用的PrepareStatement类,使用PrepareStatement类的excuteQuery(sql)来执行查询,excuteUpdata(sql)来更新。当然,我们都是在执行sql语句,但是对于Connection类、Statement类、ResultSet类、PrepareStatement类我们需要把它们关掉,不然会浪费资源。判断是否存在,若是存在,那么就.Close()关掉。

回到我们的标题,自定义连接,但是我们在执行不论是增删改查存在重复的相同的代码,我们是否可以对应的封装一下,封装成相应的工具类。那么以后我们就可以使用对应的工具类了,不用这么麻烦的写重复的代码。而且我们若是在源代码中去改连接数据库的表名、用户名、密码是不是很麻烦呢?有没有什么方法方便去修改这些经常去改变的东西呢?

我们可以使用外部文件去修改:

外部文件:文件名固定为:xxx.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf8
username=XXX
password=XXX

既然使用了外部文件,那么怎样去读取外部文件?

第一:创建ResourceBundle对象:

static {
        //表示加载命名为db.properties的外部文件
		ResourceBundle resourcebundle = ResourceBundle.getBundle("db");
		driver = resourcebundle.getString("driver");
		url = resourcebundle.getString("url");
		username = resourcebundle.getString("username");
		password = resourcebundle.getString("password");
}

第二:创建类加载器,如JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");值得注意的是需要注意加载的外部文件是db.properties

static{

        try {

InputStream is =                       

JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
			Properties prop = new Properties();
			prop.load(is);
			driver = prop.getProperty(driver);
			url = prop.getProperty(url);
			username = prop.getProperty(username);
			password = prop.getProperty(password);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

使用连接数据库若是我们封装成一个工具类或是jar包,那么以后就不需要如此的麻烦。

JDBCUtils工具包:

package utils;

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

public class JDBCUtils {
	public static String driver;
	public static String url;
	public static String username;
	public static String password;

	static {

		/*
		 * ResourceBundle resourcebundle = ResourceBundle.getBundle("db"); driver =
		 * resourcebundle.getString("driver"); url = resourcebundle.getString("url");
		 * username = resourcebundle.getString("username"); password =
		 * resourcebundle.getString("password");
		 */

		try {

			InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
			Properties prop = new Properties();
			prop.load(is);

			driver = prop.getProperty(driver);
			url = prop.getProperty(url);
			username = prop.getProperty(username);
			password = prop.getProperty(password);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public static Connection getConnection() {
		Connection conn = null;
		try {
			Class.forName(driver);
			conn = DriverManager.getConnection(url, username, password);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return conn;
	}

	public static void release(Connection conn, PreparedStatement prep, ResultSet rs) {
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		if (prep != null) {
			try {
				prep.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

}

这样就能完成连接数据库了,但是连接了数据库,但是有一个问题,我们可以调用JDBCUtils类,但是只有一个连接,若是有几个同时使用这个连接,而Connection就只有一个,那么我们可以创建一个连接池,这样就很好的解决这个问题。

二.怎样去创建一个连接池?

1.创建一个类去实现(implements)DataSource接口,且实现接口的众多方法,我们重写里面的getConnection()方法。但在之前需要创建一个容器,private static LinkedList<Connection> pool = new LinkedList<Connection>();且写出静态代码块:

private static Connection conn = null;
可以创建多个连接,但是不能一味的多,注意考虑性能就OK
	static {
		for (int i = 0; i < 5; i++) {
			conn = JDBCUtils.getConnection();
			pool.add(conn );
		}
	}

这样就可以去重写getConnection()方法了,首先判断是否还有连接,若是没有还可以创建连接,且存在容器中,在使用连接时,可以从容器中去拿取,使用pool.remove()或是pool.removeFirst()等方法,这里使用remove()方法,字面意思是移除,但是注意是从容器中移除,那就是从容器中拿取一个连接,在getConnection()方法中返回拿取的连接,这样就能有多个连接可以拿取。那么若是我们断开一个连接之后,我们得去把它放回连接池,不然连接总有拿取完的时候,在此写出一个方法backConnection(Connection conn),在pool.add(conn);完成放回连接。

public class MyDataSource2 implements DataSource {
	private static LinkedList<Connection> pool = new LinkedList<Connection>();
	private static Connection conn = null;
	static {
		for (int i = 0; i < 5; i++) {
			conn = JDBCUtils.getConnection();
			pool.add(conn);
		}
	}

	public Connection getConnection() throws SQLException {
		
		if (pool.isEmpty()) {
			for (int i = 0; i < 5; i++) {
			pool.add(conn);
			}
		}
		conn = pool.removeFirst();
		return conn;
	}
	public void backConnection(Connection conn) {
		pool.add(conn);
	}

在我测试之后,却是是可以的,但是我们返回连接是看到这个backConnection有点不习惯,若是使用原生的close()多好?那把名字修改一下就OK吧,但是我们使用的不是原生的close(),若是能直接调用close()就爽了。既然我们调用的是Connection的close()方法,那么我们就去从写一下Connection在中的close()方法,创建一个类来实现(implements)Connection,创建容器,连接Connection,创建构造方法:

public MyConnnection(Connection conn,LinkedList<Connection> pool) {
		this.conn = conn;
		this.pool = pool;
	}

重写close()方法:

public void close() throws SQLException {
		pool.add(conn);
	}

这样就可以去测试了,但是去测试的时候,会发现我们在preps = conn.prepareStatement(sql);此处出现空指针异常,为什么呢?因为我们改写了Connection,所以PrepareStatement我们也得重写:

public PreparedStatement prepareStatement(String sql) throws SQLException {
		return conn.prepareStatement(sql);
	}

既然改写了Connection,那么我们在连接池中也得改:

public class MyDataSource2 implements DataSource {
	private static LinkedList<Connection> pool = new LinkedList<Connection>();
	private static Connection conn = null;
	static {
		for (int i = 0; i < 5; i++) {
			conn = JDBCUtils.getConnection();
			MyConnnection myconn = new MyConnnection(conn, pool);
			pool.add(myconn);
		}
	}

	public Connection getConnection() throws SQLException {
		
		if (pool.isEmpty()) {
			for (int i = 0; i < 5; i++) {
				MyConnnection myconn = new MyConnnection(conn, pool);
				pool.add(myconn);
			}
		}
		conn = pool.removeFirst();
		return conn;
	}

和上面的MyDataSource相比,去掉backConnection()方法,且添加了我们重写的MyConnection类,这样就可以直接调用close()方法了。

测试jar包:junit.XX.jar和匹配jar包:hamcrest-core-XX.jar及其连接数据库的驱动mysql-connector-XX-jar包

链接:https://pan.baidu.com/s/1g6Ygnu7HGPDWsfldToPRhQ 
提取码:sp1r 

发布了9 篇原创文章 · 获赞 26 · 访问量 7762

猜你喜欢

转载自blog.csdn.net/wen123abx/article/details/100064852