时间:2021-07-01 10:21:17 帮助过:3人阅读
连接数据库的基本步骤:①注册驱动②建立连接③创建语句④执行语句⑤处理结果⑥释放资源
//需要在java工程中添加mysql连接数据库的驱动包
public void connectDatabase() throws Exception {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/jdbc";
String user = "root";
String password = "123456";
try {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.建立连接
conn = DriverManager.getConnection(url, user, password);
// 3.创建语句
st = conn.createStatement();
// 4.执行语句
rs = st.executeQuery("select * from user");
// 5.处理结果
while (rs.next()) {
System.out.println("id:" + rs.getObject(1) + "\tname:"
+ rs.getObject(2) + "\tbirthday:" + rs.getObject(3)
+ "\tmoney:" + rs.getObject(4));
}
// 6.释放资源
} finally {
try {
if (rs != null)
rs.close();
} finally {
try {
if (st != null)
st.close();
} finally {
if (conn != null)
conn.close();
}
}
}
}
! 注意不要省略释放资源的步骤
这是一个比较完整的以MySQL为例子的连接数据库的代码。 但是其有很多缺点:每进行一次连接就注册一次驱动、释放资源部分代码繁琐。因此可以对这个例子进行简单升级。升级的方式就是建立工具类用以连接数据库。
建立一个工具类,连接数据库的行为都在此工具类中定义。
public final class JdbcUtils {
private static String url = "jdbc:mysql://localhost:3306/jdbc";
private static String user = "root";
private static String password = "123456";
private JdbcUtils() {
}
// 注册驱动
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
//建立连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
//释放资源
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();
}
}
}
}
}
另外还有一种单例模式建立工具类的方式。
数据里的增删改查CRUD实际上分为2类:query(查),update(增删改)
以下代码使用到了1.2节中的工具类JdbcUtils1.java
// 增
static void create() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "insert into user(name,birthday,money)values(‘name1‘,‘1987-1-1‘,400)";
int i = st.executeUpdate(sql);
System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}
//查
static void read() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
rs = st.executeQuery("select id,name,birthday,money from user");
while (rs.next()) {
System.out.println("id:" + rs.getObject("id") + "\tname:"
+ rs.getObject("name") + "\tbirthday:"
+ rs.getObject("birthday") + "\tmoney:"
+ rs.getObject("money"));
}
} finally {
JdbcUtils.free(rs, st, conn);
}
}
//改
static void update() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "update user set money=money+10";
int i = st.executeUpdate(sql);
System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}
//删
static void delete() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "delete from user where id>=4";
int i = st.executeUpdate(sql);
System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}
前面查询用到的是Statement,它查询用到的sql语句只能通过拼接的方式产生,这样就会出现sql注入的问题。为此,可以使用PreparedStatement,它不仅解决了sql注入问题,速度也比Statement快。
PreparedStatement语法:
String sql = "select id,name from user where id=? and name=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setint(1,id); //如果不确定类型可以使用ps.setObject(1,id)
ps.setstring(2,name);
ResultSet rs = ps.executeQuery();
可以使用分层的思想对以上代码进行组织,创建JDBC的Dao访问层。UserDao
JDBC查询出的结果集包含了部分元数据,如结果集数据个数、列名等。可以利用这些元数据,将查询出的结果集封装成Map。
public static List<Map<String, Object>> read(String sql) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
//获取结果集元数据
ResultSetMetaData rsmd = rs.getMetaData();
//列数
int count = rsmd.getColumnCount();
//列名
String[]colNames=new String[count];
for(int i=1;i<=count;i++){
colNames[i-1]=rsmd.getColumnName(i);
}
List<Map<String, Object>>datas=new ArrayList<Map<String,Object>>();
while(rs.next()){
Map<String ,Object>data=new HashMap<String, Object>();
for(int i=0;i<colNames.length;i++){
data.put(colNames[i], rs.getObject(colNames[i]));
}
datas.add(data);
}
return datas;
} finally {
JdbcUtils.free(rs, ps, conn);
}
}
利用封装后的Map能够更好的对结果集进行操作。
除了将结果集封装成Map,还可以使用反射(反射1,反射2)将结果集封装成Object,然后再根据具体的需要转成想要的对象。
// 将数据库中读出的数据放到新建的User对象中,返回User对象
static User getUser(String sql) throws Exception {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
String[] colNames = new String[count];
for (int i = 1; i <= count; i++) {
colNames[i - 1] = rsmd.getColumnName(i);
}
User user = null;
while (rs.next()) {
user = new User();
Method[] ms = user.getClass().getMethods();
for (int i = 0; i < colNames.length; i++) {
String colName = colNames[i];
String methodName = "set" + colName; // set方法的名字
for (Method m : ms) {
if (methodName.equals(m.getName()))
m.invoke(user, rs.getObject(colName));
}
}
}
return user;
} finally {
JdbcUtils.free(rs, ps, conn);
}
}
之前的例子中,每次程序结束都会关闭连接,这样太浪费资源,(因为在以此数据库查询中,最耗时间的就是建立连接的过程)可以使用连接池的方式优化。
程序开始的时候创建一批连接,放入连接池中,当需要使用的时候就从连接池中取连接,使用完毕后再将连接放回到连接池中。
基本步骤:
LinkedList<Connection>
作为连接池;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
public class MyDataSource {
private static String url = "jdbc:mysql://localhost:3306/jdbc";
private static String user = "root";
private static String password = "123456";
private LinkedList<Connection> connectionPool = new LinkedList<Connection>(); //连接池
public MyDataSource(){
try{
for(int i=0;i<10;i++){ //MyDataSource创建时就建立10个连接
this.connectionPool.addLast(this.createConnection());
}
}catch(SQLException e){
throw new ExceptionInInitializerError();
}
}
public Connection getConnection(){
return this.connectionPool.removeFirst();
}
public void free(Connection conn){ //释放连接,实际上就是重新加入到连接池
this.connectionPool.addLast(conn);
}
private Connection createConnection()throws SQLException{
return DriverManager.getConnection(url,user,password);
}
}
因此,工具类也要相应的修改,如工具类,即
以上只是一个最简单的连接池的示例,还可以对其进行一些优化,见连接池优化,如
在以上的示例中,关闭连接(即将连接放回list中)使用的是自己定义的free()
方法,但是在JDBC中默认的关闭连接是close()
方法。为了避免连接被意外用close关闭,要修改connection的close方法,如代理模式重写close方法:
在代理模式重写close方法中,实现Connection接口时实现了其中的全部方法。这显然很麻烦,可以使用动态代理的方式对其进行改进。
在实际的使用中,很少会手动建立连接池和数据源,现有框架已经提供了很好的封装。因此,本章内容只做了解即可。
前面提到了数据源,并且写了几个数据源例子,但是都没有实现DataSource接口。
数据源有很多好处:
虽然数据源有这么多优点,但是实现起来太麻烦,好在现在有很多开源实现,比如一个现成的数据源:Apache DBCP
使用DBCP
1 添加包commons-dbcp-1.2.2.jar
、commons-collections-3.1.jar
、commons-pool.jar
2 配置文件
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=123456
#初始化连接
initialSize=10
#最大连接数量
maxActive=50
#最大空闲连接
maxIdle=20
#最小空闲连接
minIdle=5
#超时等待时间以毫秒为单位 6000毫秒/1000等于60秒
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
3 修改工具类
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public final class JdbcUtils {
private static DataSource myDataSource = null;
private JdbcUtils() {
}
static {
try {
Properties prop = new Properties();
InputStream is = JdbcUtils.class.getClassLoader()
.getResourceAsStream("dbcpconfig.properties");
prop.load(is);
myDataSource = BasicDataSourceFactory.createDataSource(prop); // 屏蔽了创建数据源的过程
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws SQLException {
// return DriverManager.getConnection(url, user, password);
return myDataSource.getConnection(); // 取连接
}
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 (Exception e) {
e.printStackTrace();
}
}
}
}
}
JdbcTemplate是由spring框架提供的一个工具类,他对Jdbc API提供了很好的封装,可以用来完全替代JDBC API。
JDBC
标签: