博主声明:
转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。
本文首发于此 博主:威威喵 | 博客主页:https://blog.csdn.net/smile_running
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。(官方语言描述,看看就好。)
JDBC,它就像驱动一样,数据库比如:mysql、oracle、db2、sqlSever等,不同的产商肯定实现的方式都不一样,那就要求程序员得每一个数据库的操作都得学会,只有这样才能跟上需求的改变。所以,JDBC,它就站出来了。它为每个产商提供相同的接口,不管数据库底层如何实现。相当于在数据库与应用程序中间加了一层,这就是 JDBC。那么,加了这一层,程序员们就可以通过 JDBC 固定 API 来操作各种不同数据库了,相当机智。
代码如下:
public class JdbcUtils {
public static Connection getConnection() throws Exception {
/**
* 步骤:
* 1. 声明 driver、jdbcUrl、user、password 四个变量
* 2. 新建 jdbc.properties 配置文件,使其在不改源码情况下,变更数据库
* 3. 获取 jdbc.properties 文件参数,利用Java反射和输入流方式获取
* 4. Class.forName(driver);加载驱动
* 5. 获取连接实例
*/
String driver = null;
String jdbcUrl = null;
String user = null;
String password = null;
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
properties.load(inputStream);
driver = properties.getProperty("driver");
jdbcUrl = properties.getProperty("jdbcUrl");
user = properties.getProperty("user");
password = properties.getProperty("password");
Class.forName(driver);
Connection conn = (Connection) DriverManager.getConnection(jdbcUrl, user, password);
return conn;
}
public static void release(Statement statement, Connection conn, ResultSet result) {
try {
if (statement != null) {
statement.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (result != null) {
result.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里我写了一个Jdbc获取连接的工具类,只要调用 getConnection() 方法就可以连接成功了。注意一点:MySQL 数据库连接参数为如下(也就是上面代码中注释部分 jdbc.properties 文件内容),否则将连不上,MySQL 端口和用户名都是默认的。
上图的 person 代表的是你的数据库名称。
数据库为上文 user 表(图在上面)
增、删、改方法
public class JdbcTest {
/**
* 提供: 增 、删、改3个功能的通用方法
*
* @param sql
* @param args sql 中占位符的值,可以用多个逗号隔开
*/
public void update(String sql, Object... args) throws Exception {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils.getConnection();
System.out.println(sql);
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
preparedStatement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.release(preparedStatement, connection, null);
}
}
@Test
public void insert() throws Exception {
String sql = "INSERT INTO user(user_name,sex,user_role,password,id_card,register_time)"
+ " VALUES(?,?,?,?,?,?)";
update(sql,"小红","女","VIP用户","xh","654...","2019-01-25 14:02:03");
}
@Test
public void delete() throws Exception {
// 删除 user 表中 user_name 为小红的信息
String sql = "DELETE FROM user WHERE user_name=?";
update(sql,"小红");
}
@Test
public void modify() throws Exception {
// user 表中 user_name 为小红 的用户,将其 user_role 改为 普通用户
String sql = "UPDATE user set user_role=? WHERE user_name=?";
update(sql,"普通用户","小红");
}
}
通用查询方法封装
利用面向对象编程的思想,我们新建了一个 User 类,此类变量为 user 表对应的列名,代码如下:
package com.xww;
public class User {
public String userName;
public String password;
public String registerTime;
public String sex;
public String userRole;
public String idCard;
public User(String userName, String password, String registerTime,
String sex, String userRole, String idCard) {
super();
this.userName = userName;
this.sex = sex;
this.userRole = userRole;
this.password = password;
this.idCard = idCard;
this.registerTime = registerTime;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getUserRole() {
return userRole;
}
public void setUserRole(String userRole) {
this.userRole = userRole;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public String getRegisterTime() {
return registerTime;
}
public void setRegisterTime(String registerTime) {
this.registerTime = registerTime;
}
@Override
public String toString() {
return "User [userName=" + userName + ", password=" + password + ", registerTime=" + registerTime + ", sex="
+ sex + ", userRole=" + userRole + ", idCard=" + idCard + "]";
}
}
那么查询 user 表的方法就可以写为这样(不够灵活):
public User query(String sql) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
User user = null;
try {
connection = JdbcUtils.getConnection();
System.out.println(sql);
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
user = new User(resultSet.getString(2), resultSet.getString(3), resultSet.getString(4),
resultSet.getString(5), resultSet.getString(6), resultSet.getString(7));
System.out.println(user.toString());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.release(preparedStatement, connection, resultSet);
}
return user;
}
这样的确可以获取到 user 表,但是这个方法并不能通用。例如:我想查询 student 表时,student 表中字段名与 user 表肯定不一样,这样就会产生错误。所以,这种情况就可以利用 Java 反射来实现。可是,User 类中的变量相当于 user 表中的列名,如果让 User 类将变量名强制写成 user 表中一样,那就显得很局限,不能够通配。那么,就得用到 JDBC 提供的另一个接口了。
(1)ResultSetMetaData 接口
它用于获取 ResultSet 结果集的元数据,用处是在于从查出的结果集中获取相应的列数、列名等。常用方法如下:
(2)利用 sql 语句添加别名的方式
比如我要查询 user 表中 ‘小王’ 的详细信息,原本的 sql 语句:
> SELECT * FROM user WHERE user_name='小王'
要改为添加别名的方式,注意:别名一定是与User类中定义变量名一致,否则在反射时将找不到字段:
> SELECT user_name userName,password password,register_time registerTime,sex sex,user_role userRole,id_card idCard FROM user WHERE user_name='小王'
查出来的结果如下图:
字段名都与 User 类中的变量名相一致了。
(3)利用 Java 反射给 User 类中的每个属性变量赋予值 .
那么,经过这几翻的处理,我们的 User 类终于可以匹配数据库了。这个虽说可以实现通用查询,映射到实体类中,但明显在 sql 语句中那么点缺乏简练。整个查询代码如下:
public class JdbcTest {
/**
* 利用 Java 反射机制,写的一个通用查询方法
*
* @param sql
*/
public T query(Class clazz, String sql, Object... args) {
T entity = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
User user = null;
try {
connection = JdbcUtils.getConnection();
// System.out.println(sql);
preparedStatement = connection.prepareStatement(sql);
if (args != null) {
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
}
resultSet = preparedStatement.executeQuery();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
Map values = new HashMap();
if (resultSet.next()) {
for (int i = 0; i < resultSetMetaData.getColumnCount(); i++) {
String columnLable = resultSetMetaData.getColumnLabel(i + 1);
Object columnValue = resultSet.getObject(i + 1);
values.put(columnLable, columnValue);
}
}
System.out.println("--->数据库:"+values);
if (values.size() > 0) {
entity = (T) clazz.newInstance();
for (Entry entry : values.entrySet()) {
String fieldName = entry.getKey();
Object fieldValue = entry.getValue();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(entity, fieldValue);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.release(preparedStatement, connection, resultSet);
}
return entity;
}
@Test
public void qurey() {
String sql = "SELECT user_name userName,password password,register_time registerTime,"
+ "sex sex,user_role userRole,id_card idCard FROM user WHERE user_name=?";
User user = query(User.class, sql, "小王");
System.out.println("--->反射到 User 类中:"+user.toString());
}
}
(4)BeanUtils 工具包
BeanUtils 工具包是 Apache 出的一个辅助工具,主要方便对于 JavaBean 进行一系列的操作。例如:
BeanUtils 工具类的常用方法如下:
现在我们导入 beanutils.jar 包和一个依赖的 loggin.jar 包:
修改上面部分代码:
将 Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(entity, fieldValue);修改为 BeanUtils.setProperty(entity, fieldName, fieldValue);
运行代码,匹配数据库成功,并反射到 User 类中: