Java开发系列--JDBC(从基础到封装)

     JDBC全称是Java DataBase Connectivity,即Java数据库连接,它是一种可以执行SQL语句的Java API。

     Java API是接口,其实现类由各数据库厂商提供实现,这些实现类就是“驱动程序”。

     

    正是通过JDBC驱动的转换,才使得使用相同JDBCAPI编写的程序,可以在不同的数据库系统上运行良好。

   下面是JDBC编程步骤,以MySQL为例:

   查询操作:

Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try {
	//加载驱动
        Class.forName("com.mysql.jdbc.Driver");
	//使用driverManager获取数据库链接
	//获取connection代表了java程序和数据库的链接
	conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/lcma", "root", "iflytek");
	//使用conncetion创建一个statement对象
	stat = conn.createStatement();
	//执行sql语句
	rs = stat.executeQuery("select * from student");
	//不断使用next()将指针下移一行
	while(rs.next()){
		System.out.println(rs.getString("name"));
	}
} catch (Exception e) {
	e.printStackTrace();
}finally{
	if(rs != null){try{rs.close();}catch(SQLException e){e.printStackTrace();}}
	if(stat != null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}}
        if(conn != null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}
}

  增删改查操作:
Connection conn = null;
Statement stat = null;
try {
	//加载驱动器
	Class.forName("com.mysql.jdbc.Driver");
	//通过driverManager获取数据库链接
	conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/lcma", "root", "iflytek");
	//使用Connection创建一个Statement
	stat = conn.createStatement();
	//执行SQL(insert/update/delete)语句,返回数据库影响的行数
	int rows = stat.executeUpdate("insert into student (id,name,age,cla_id) values (2,'马小超',22,1)");
	if(rows == 1){
		System.out.println("插入成功");
	}
} catch (Exception e) {
	e.printStackTrace();
}finally{
	//释放资源
	if(stat != null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}}
        if(conn != null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}
}

通过对前面代码的分析,会发现以下几个问题:

•Url、User、Password直接在代码中定义,如果数据库服务器稍作变动,怎么办?
•一个项目基本针对一个底层数据库,难道每次操作数据库,都要注册一次驱动程序嘛?是否可以只注册一次?
•获取数据库连接时,每次都需要Url、User、Password,一旦改动其中一个数据,意味着要修改所有此处的代码。
•释放资源,每次数据库操作后,都需要释放资源,难道每次操作后都要写三次try close catch代码嘛?

如果要解决上面的几个问题,那么就要对刚才的代码实现封装,并且把数据库的配置放到配置文件(Properties)中,具体做法如下:
新建jdbc.properties,


内容如下:

#数据库连接配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/lcma?characterEncoding=utf-8
user=root
password=iflytek

新建一个JdbcUtil类,实现代码如下:

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;

public class JdbcUtil {

	private static String url;
	private static String user;
	private static String password;
	
	static{
		//使用properties加载属性文件
		Properties prop = new Properties();
		try {
			InputStream is = JdbcUtil.class.getClassLoader().getResourceAsStream("com/iflytek/jdbc.properties");
			prop.load(is);
			//注册驱动(获取属性文件中的数据)
			String driverClassName = prop.getProperty("driverClassName");
			Class.forName(driverClassName);
			//获取属性文件中的url,username,password
			url = prop.getProperty("url");
			user = prop.getProperty("user");
			password = prop.getProperty("password");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	//获取数据库连接
	public static Connection getConnection(){
		Connection conn = null;
		try {
			conn = DriverManager.getConnection(url, user, password);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}
	
	//释放资源
	public static void close(Connection conn, Statement stat, ResultSet rs){
	     if(conn != null){
	    	 try {conn.close();} catch (SQLException e) {e.printStackTrace();}
	     }
	     if(stat != null){
	    	 try {stat.close();} catch (SQLException e) {e.printStackTrace();}
	     }
	     if(rs != null){
	    	 try {rs.close();} catch (SQLException e) {e.printStackTrace();}
	     }
	}
}

在加载配置文件的时候使用了静态代码块,表明类一加载,配置文件就会立马加载,属性被保存在静态变量中(url,user,password)。

获取数据库连接和释放资源都采用了静态方法,通过类直接调用改方法,实现了公用代码的封装,降低的代码的耦合性。

这时候我们再来看JDBC获取数据库数据代码:

Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try{
    //通过JdbcUtil获取数据库链接
    conn = JdbcUtil.getConnection();
    stat = conn.createStatement();
    rs = stat.executeQuery("select * from student");
    while(rs.next()){
         System.out.println(rs.getString("name"));
    }
}catch(Exception e){
    e.printStackTrace();
}finally {
    //通过JdbcUtil关闭资源
    JdbcUtil.close(conn, stat, rs);
}

通过现在的代码可以看出,代码简介了很多,没有出现容易出错的配置,获取连接,加载配置文件,关闭资源我们也不需要关心,大大降低了代码的耦合性,提高了代码重用性。

封装过后的代码还是有些问题,就是采用了Statement对数据库操作,如果现在SQL语句需要传入变量,只有采用拼接的方式,这样做有很多缺点,例如拼接容易出错或容易产生SQL注入等。

通过PreparedStatement对数据库操作可以解决Statement带来的缺点,PreparedStatement和Statement区别如下:

Statement的缺点:

•同样的SQL语句,每次都要发送,不能进行有效的缓存。
•拼接SQL字符串非常容易出现错误。
•不能防止恶意数据,易产生SQL注入。

升级后的新接口PreparedStatement(推荐):

•预编译SQL语句,并进行有效的缓存,性能更好。
•允许使用问号占位符参数,并且该参数必须获得值后才可以执行。
•无需拼接SQL语句。

问号占位符参数:INSERTINTO User(id,name,age,birthday)VALUES(?,?,?,?); 

来看一下通过PreparedStatement对数据库操作的代码:

Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
try{
        //通过JdbcUtil获取数据库链接
	conn = JdbcUtil.getConnection();
	stat = conn.prepareStatement("select * from student where name like ? and age = ? ");
	stat.setString(1, "%小%");
	stat.setInt(2, 22);
	rs = stat.executeQuery();
	while(rs.next()){
	       System.out.println(rs.getString("name"));
	}
	}catch(Exception e){
	       e.printStackTrace();
	}finally {
		//通过JdbcUtil关闭资源
		JdbcUtil.close(conn, stat, rs);
	}
}

注意以下两点:

1.问号占位符不能加引号。

2.占位符参数设置值从下标从1开始。









  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值