JDBC框架
初识JDBC
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序,同时,JDBC也是个商标名。
在JDBC出现以前,早期的java需要访问数据库时,需要根据不同的数据库管理系统(DBMS)编写不同的数据源,使用一项称之为JDBC-ODBC桥链接模式。
通过以上访问方式,程序员会在访问数据方面花费大把精力,因此SUN在后来设计的JDBC接口,将访问数据库的具体实现交给不同的数据库厂商各自实现,从而减轻java程序员的压力
相关接口
DriverManage:驱动管家类,java.sql中提供的一个具体类,内部包含了一些用于加载数据库驱动的方法以及获取连接的操作:`getConnection
Connection:用于表示从Java程序到数据库的连接通道,通过Connection可以向数据库传输sql命令,并且返回执行结果.另外Connection也可以用于对数据库事务管理
Statement/PrepareStatement:Statement是一个用于执行sql命令的对象,主要用于执行静态sql(事先准备好的,固定的);由于Statement的固有不安全性(很有可能导致sql注入的风险),因此还提供一个直接子接口:PreparedStatement(预处理命令对象),可以有效的防止sql注入的风险
ResultSet:结果集对象,用于表示对于查询语句执行之后的结果,内部的数据可能是一条也可以是多条
使用JDBC的六个步骤
1、加载驱动
2、获取连接
3、获取执行sql语句的对象
4、执行
5、处理结果
6、关闭资源
下面是六个步骤的代码(以PrepareStatement进行演示)
public class JDBCQuery {
public static void login2(int sno,String sname) throws ClassNotFoundException, SQLException {
String sql = "select * from stu where sno=? and sname=?";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/datebase","user","password");
//3.获取预处理sql命令的对象
PreparedStatement ps= conn.prepareStatement(sql);
//预处理
ps.setInt(1, sno);
ps.setString(2, sname);
//4.执行
ResultSet rs = ps.executeQuery();
//5.处理结果
if(rs.next()) {
System.out.println("登陆成功");
}else {
System.out.println("请检查账号和密码");
}
//6.关闭资源
rs.close();
ps.close();
conn.close();
}
JDBC的封装
当我们每一次连接数据库时都需要加载驱动,获取连接,当操作方法过多时,就会造成大码的大量重复,并且浪费时间,因此首先先将加载驱动和获取连接以及关闭资源操作封装起来。
/**
* 获取数据库连接对象
* @return
*/
public static synchronized Connection getConn() {
try {
return DriverManager.getConnection(URL, USER, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 关闭资源操作
* @param rs
* @param stat
* @param conn
*/
public static void close(ResultSet rs, Statement stat,Connection conn) {
try {
if (rs!=null)rs.close();
if (stat != null)stat.close();
if (conn != null)conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
获得连接的方法上需要加锁,保证每一次连接都只能有一个用户对数据进行操作,防止并发操作时造成数据不一致问题。
只要访问数据库,只需要调用这个方法就可以了。
对于数据的操作无非就是增删查改,并且添加、更新、删除这三个方法执行完后不需要返回数据的集合,只需要告诉我执行成功或失败就行了,因此返回值都是boolean类型的,那么就可以对这三个方法进一步封装为一个方法。
/**
* 封装通用的更新操作:INSERT,UPDATE,DELETE
* @param sql
* @param params
* @return
* @throws SQLException
*/
public static boolean exeUpdate(String sql,Object...params) {
Connection conn = getConn();
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(sql);
if (params!=null) {
for(int i =0; i<params.length;i++) {
ps.setObject(i+1, params[i]);
}
}
return ps.executeUpdate()>0;
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(null, ps, conn);
}
return false;
}
只需要根据结果true or false 就可以知道该操作是否成功,一行代码就可以解决。
接下来封装查询操作,根据用户的选择又可以将查询分为单条数据查询和多条数据查询,该操作会返回一条或多条数据,所以返回值是一个集合,一个map集合。执行查询语句后得到一个结果集,再使用ResultSetMetadata,将表中的每一条数据使用map集合以键值对的形式存入,再将map对象转换为实体类对象输出。
1、首先获取到数据的map对象
这里需要获得表中每一条数据的列名以及对应的值,需要使用到ResultSetMetaData。可以获取到每一行的列属性及对应的值。
/**
* 执行相关查询并将结果返回为List<Map<String, Object>> 集合
* @param sql
* @param params
* @return
*/
public static List<Map<String, Object>> queryMaps(String sql,Object...params){
List<Map<String, Object>> list = new ArrayList<Map<String,Object>>()