JDBC(MySQL)一周学习总结(一)
首先我们从获取 JDBC 连接开始
Driver(每个驱动程序类必须实现的接口)
获取数据库连接需要配置数据库连接信息,DriverClass 表示数据库驱动,user 表示数据库登录用户名,passWord 表示登录密码,url 用于标识一个被注册的驱动程序,驱动程序管理器通过 URL 选择正确的驱动程序,从而建立数据库连接
Oracle URL:jdbc:oracle:thin:@localhost:1521:数据库名
SQLServer URL:jdbc:microsoft:sqlserver//localhost:1433;DatabaseName=数据库名
MySQL URL:jdbc:mysql://localhsot:3306/数据库名;如果你的mysql 数据库默认端口没有改变其 URL 可以简写为 jdbc:mysql:///数据库名
下面就是获取数据库连接的代码:
package com.java.jdbc.test; import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Properties; import org.junit.Test; public class TestConnection { // DriverClass 利用不通的构造器去创建一个对象
@Test
public void testDriver() throws SQLException {
// 连接数据 Mysql
Driver driver = new com.mysql.jdbc.Driver();
// 准备数据库连接信息
String url = "jdbc:mysql://localhost:3306/sh_db"; Properties info = new Properties();
// 我们除了可以利用 put 方法将连接信息存入 properties 对象,还可以利用 setProperty 去设置属性
// 用户名
info.put("user", "root");
// 密码
info.put("password", "zy961029"); Connection connection = driver.connect(url, info);
// 打印数据库连接信息
System.out.println(connection);
}
}
上面的代码是最基本的连接数据库的实现,但是我们要使用上面的代码去实现连接不同的数据库的时我们就需要去改变源代码中的数据库信息,这样做肯定是不方便,且容易出错的,所以我们接下来实现利用外部配置文件的去实现获取数据库连接
package com.java.jdbc.test; import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.util.Properties; import org.junit.Test; public class TestConnection { // 此方法具有普遍性,在本方法中没有和任何数据库厂商相连接,只需要改变配置文件即可达到连不同的数据库
public Connection getConnection() throws Exception {
String driverClass = null;
String url = null;
String user = null;
String password = null; InputStream in = getClass().getClassLoader().getResourceAsStream("jdbc.properties"); // 通过反射获得配置文件,用 properties 类来获取配置文件的属性
Properties properties = new Properties();
properties.load(in);
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password"); Driver driver = (Driver) Class.forName(driverClass).newInstance(); Properties info = new Properties();
info.put("user", user);
info.put("password", password); Connection connection = driver.connect(url, info); return connection;
}
} jdbc.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/sh_db
user=root
password=zy961029
DriverManager
管理一组 JDBC 驱动程序的基本服务,可以通过重载的 getConnection() 获取连接更加方便,可以同时管理多个驱动程序,若注册了多个数据库驱动,只需要给 getConnection 方法传入不同的参数即可,下面是利用 DriverManager 获取数据库连接
@Test
public void getConnection() {
// 通过反射获取配置文件
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
try {
// 获取属性属性值
properties.load(inputStream);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driverClass"); // 加载数据库驱动类(注册驱动)
// 注册驱动本应如下注册,但在 com.mysql.Driver 中的静态代码块已经将其注册了,所以不需在写一遍
// DriverManager.registerDriver(Class.forName(driver).newInstance());
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, password);
System.out.printf(String.valueOf(connection));
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} }
通过上面的介绍我们现在获取到了数据库的连接,那么接下来就是操作数据库(增删改查,首先利用 Statement,使用完毕需要释放)
@Test
public void testInser() {
// 获取数据库连接
Connection connection = getConnectionMy();
// statement 对象是操作 sql 语句的对象
Statement statement = null;
try {
// 获取 statement 对象
statement = connection.createStatement(); String sql = null;
// sql = "INSERT INTO book (BOOK_NAME, ISBN, PRICE, STOCK) VALUES ('SQLServer', '1004', '150', '30' )";
// sql = "DELETE FROM book WHERE id=4";
sql = "UPDATE book SET PRICE=400 WHERE id=5";
// 执行 sql 语句
statement.execute(sql);
System.out.printf("Success");
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
// 关闭连接以及 statement
if (statement != null) {
statement.close();
} if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上面的插入操作我们看到其所需要的 sql 语句需要的是完整的,当我们插入的值非常多的时候这样拼写 sql 语句就显得有点不适合,所以我们需要去学习 PrepareStatement,它可以用 ? 代表插入值,以及更新和删除操作需要传入的参数,同时也需要利用 setXxx 方法去为每一个 ? 赋值
@Test
public void testUpdateWithPrepare() {
Connection connection;
PreparedStatement preparedStatement = null; connection = JDBCTools.getConnection(); String sql = "INSERT INTO book (BOOK_NAME, ISBN, PRICE, STOCK) VALUES (?, ?, ?, ?)"; try {
// 获得 prepareStatement 对象
preparedStatement = connection.prepareStatement(sql);
// 为每一列赋值,需要传入下标,从 1 开始
preparedStatement.setString(1, "C#");
preparedStatement.setString(2, "1008");
preparedStatement.setString(3, "320");
preparedStatement.setInt(4, 120);
// 执行更新操作
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTools.releaseUpdate(preparedStatement, connection);
}
}
接下来我们介绍如何进行查的操作,首先需要了解 ResultSet 接口(使用完毕需要释放资源)
ResultSet 封装了 JDBC查询的结果集,并返回一张数据表,并有一个指针指向数据表的第一行,我们调用 next() 方法检测下一行是否有效,若为 true 则下移,我们可以利用 getXxx() 方法获取每一行对应的值
@Test
public void testSelect() {
Connection connection = getConnectionMy();
Statement statement = null;
String id = null;
String bookName = null;
String isbn = null;
// 执行查询操作的对象
ResultSet resultSet = null;
String sql = null; try {
sql = "SELECT BOOK_NAME, ISBN, PRICE, STOCK from book WHERE id=5";
// 获取 statement 对象
statement = connection.createStatement();
// 执行查询操作
resultSet = statement.executeQuery(sql); // 处理 resultSet,首先需要判断其是否
if (resultSet.next()) {
// 获得对应的列的值
id = resultSet.getString(1);
bookName = resultSet.getString(2);
isbn = resultSet.getString(3);
} System.out.printf(id + "; " + bookName + "; " + isbn);
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
} if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
通过上面的方法我们可以体会到每次关闭连接以及以后每次进行相应的操作的时候我们不可能像这样每次都写完整的代码,我们应该像封装获取连接的函数一样去封装其其他方法,写为一个工具类
package jdbc.example.test.myself; import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties; public class JDBCTools { /*
* 关闭数据库连接资源
* */
public static void release(Statement statement, Connection connection, ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} /*
* 获取数据库连接
* */
public static Connection getConnection() {
String user;
String password;
String url; Connection connection = null; InputStream inputStream = JDBCTools.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
try {
properties.load(inputStream); user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url"); connection = DriverManager.getConnection(url, user, password);
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} return connection;
} /*
* 执行数据库操作,除查询操作
* */
public static void update(String sql) {
Connection connection;
Statement statement = null; connection = getConnection();
try {
statement = connection.createStatement();
statement.executeUpdate(sql);
} catch (SQLException e) {
e.printStackTrace();
} finally {
releaseUpdate(statement, connection);
}
}
}
现在我们的工具类中并没有通用的查询方法,为了完善我们的工具类我们需要学习 JavaBean 和 ResultSetMetaData
JavaBean 其实就是普通的 java 类,不同的是没有 main 方法,只包含变量和对应的 set、get 方法,数据表对应的类就需要用 JavaBean 去写,其变量名对应数据表的列名,若列名为两个单词那么对应的变量名的第二个单词需大写,如:book_name --> bookName,isbn --> isbn
ResultSetMetaData 是描述 ResultSet 元数据的接口,它可以获取到结果集有多少列,以及列名和列的别名
我们都已经知道 ResultSet 返回的是一张数据表,如果我们还像以前那样在方法中为每一列新建一个变量,就不能完成通用的查询方法,所以我们需要为每张数据表创建一个对应的类,用 JavaBean 的规则。这样 ResultSet 结果集的每一行对应一个对象。
在方法中我们可以利用 ResultSetMetaData 获得结果集中列的别名,以及从结果集中获得对应的值,我们将其存为一个键位列名,值为列值的键值对,方便后面为数据表对应的对象赋值以便打印。
注意:在测试方法中书写 SQL 语句的时候,我们应该向 javaBean 看齐,也就是如果数据表对应的列名为两个单词,那么就应该为其起一个别名,和 JavaBean 对应的变量名统一,如果没有统一,将打印 null!
// 通用的查询方法,clazz 为数据表对应的类
public <T> T get(Class<T> clazz, String sql, Object ... args) {
T entity = null; Connection connection;
PreparedStatement preparedStatement;
ResultSet resultSet;
ResultSetMetaData resultSetMetaData;
// 存储列名以及列值
Map<String, Object> map = new HashMap<String, Object>(); connection = JDBCTools.getConnection();
try {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(1, args[i]);
}
resultSet = preparedStatement.executeQuery();
resultSetMetaData = resultSet.getMetaData(); if (resultSet.next()) {
for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
map.put(resultSetMetaData.getColumnLabel(i), resultSet.getObject(i));
}
} // 判断 map 中是否有值,若有则利用反射创建对象,并为之赋值
if (map.size() > 0) {
entity = clazz.newInstance();
// 利用for 循环为每一个变量赋值
for (Map.Entry<String, Object> entry: map.entrySet()) {
String fieldName = entry.getKey();
Object fieldValue = entry.getValue(); Field field = clazz.getDeclaredField(fieldName);
// 打破封装
field.setAccessible(true);
field.set(entity, fieldValue);
}
} System.out.printf(String.valueOf(entity));
} catch (SQLException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} return entity;
}
@Test
public void testSelect() {
String sql = "SELECT id, BOOK_NAME bookName, isbn, price, stock FROM book WHERE id = ?";
// testSelect(SH_DB.class, sql, 5);
get(SH_DB.class, sql, 6);
}
package com.jdbc.dao.my.first.test; /**
* Created by shkstart on 2017/10/31.
*/
public class SH_DB {
private String bookName;
private String isbn;
private int price;
private int stock; public SH_DB() {
} public SH_DB(String bookName, String isbn, int price, int stock) {
this.bookName = bookName;
this.isbn = isbn;
this.price = price;
this.stock = stock;
} public String getBookName() {
return bookName;
} public void setBookName(String bookName) {
this.bookName = bookName;
} public String getIsbn() {
return isbn;
} public void setIsbn(String isbn) {
this.isbn = isbn;
} public int getPrice() {
return price;
} public void setPrice(int price) {
this.price = price;
} public int getStock() {
return stock;
} public void setStock(int stock) {
this.stock = stock;
}
// 为了方便打印重写 toString 方法
@Override
public String toString() {
return "SH_DB{" +
"bookName='" + bookName + '\'' +
", isbn='" + isbn + '\'' +
", price=" + price +
", stock=" + stock +
'}';
}
}
对应的 JavaBean
上面我们利用反射的方式对数据表对象进行了赋值操作,我们还可以利用一个 beanUtils (在使用之前必须导入 beanUtils jar 包和它所依赖的 commons-logging jar 包)工具类为其赋值 BeanUtils.setProperty(class, fieldName, fieldValue);
现在我们可以将工具类方法进行完善以及将其进行重构,包括了查询多条记录,查询单条记录,查询单个值,更新等操作,如下:
package com.jdbc.dao.my.first.test; import org.apache.commons.beanutils.BeanUtils; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.*; /**
* Created by shkstart on 2017/10/31.
*/ /*
* Dao -> Data Access Object
* 包括了对数据库 CRUD (Create read update delete) 操作,而不包含任何业务逻辑信息
* 可以实现功能模块化,便于维护
* */
public class DaoOfMy { // 更新数据库的方法,可能是删除,更新,增加操作
public void update(String sql, Object... args) {
Connection connection;
PreparedStatement preparedStatement = null; connection = JDBCTools.getConnection();
try {
preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
} preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTools.releaseConnection(connection, preparedStatement, null);
}
} // 查询一条记录
public <T> T get(Class<T> clazz, String sql, Object... args) {
T entity = null; Connection connection;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
ResultSetMetaData resultSetMetaData = null;
Map<String, Object> map = new HashMap<String, Object>(); connection = JDBCTools.getConnection();
try {
preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
} resultSet = preparedStatement.executeQuery();
resultSetMetaData = resultSet.getMetaData(); if (resultSet.next()) {
for (int i = 0; i < resultSetMetaData.getColumnCount(); i++) {
String colLabel = resultSetMetaData.getColumnLabel(i + 1);
Object colVal = resultSet.getObject(i + 1);
map.put(colLabel, colVal);
}
} if (map.size() > 0) {
entity = clazz.newInstance();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String fieldName = entry.getKey();
Object fieldVal = entry.getValue();
setFieldVal(entity, fieldName, fieldVal);
}
} } catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} finally {
JDBCTools.releaseConnection(connection, preparedStatement, resultSet);
} return entity;
}
//查询多条记录
public <T> List<T> getForList(Class<T> clazz, String sql, Object... args) {
// 存取所有对象
List<T> entities = new ArrayList<T>(); Connection connection;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null; connection = JDBCTools.getConnection();
try {
preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
} resultSet = preparedStatement.executeQuery(); // 存取查询到的多条记录
List<Map<String, Object>> listMap = handleResultSetToMapList(resultSet);
// 存取对象集合
entities = changeMapListToBeanList(clazz, listMap); } catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} finally {
JDBCTools.releaseConnection(connection, preparedStatement, resultSet);
} return entities;
} private <T> List<T> changeMapListToBeanList(Class<T> clazz, List<Map<String, Object>> listMap) throws InstantiationException, IllegalAccessException { List<T> entities = new ArrayList<T>();
T entity2;
if (listMap.size() > 0) { Iterator<Map<String, Object>> iterator = listMap.iterator(); while (iterator.hasNext()) {
entity2 = clazz.newInstance();
for (Map.Entry<String, Object> entry : iterator.next().entrySet()) {
String fieldName = entry.getKey();
Object fieldVal = entry.getValue();
setFieldVal(entity2, fieldName, fieldVal);
}
entities.add(entity2);
}
}
return entities;
} // 处理结果集,将查询到的每一条结果集存入到 List 中
private List<Map<String, Object>> handleResultSetToMapList(ResultSet resultSet) throws SQLException { List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
// 存取查询结果中的一条记录
Map<String, Object> map;
while (resultSet.next()) {
// 每次都将 map 对象 new 一下,这样每次就是不同的值,不会出现一直存取第一个值
map = new HashMap<String, Object>();
for (int i = 0; i < resultSetMetaData.getColumnCount(); i++) {
String colLabel = resultSetMetaData.getColumnLabel(i + 1);
Object colVal = resultSet.getObject(i + 1);
map.put(colLabel, colVal);
}
mapList.add(map);
}
return mapList;
} public void setFieldVal(Object obj, String fieldName, Object fieldVal) {
// Field field;
try {
// 使用反射赋值
// field = obj.getClass().getDeclaredField(fieldName);
// field.setAccessible(true);
// field.set(obj, fieldVal);
// 使用 BeanUtils 操作类的属性
BeanUtils.setProperty(obj, fieldName, fieldVal);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} // 获取单个值
public int getForValue(String sql) {
Connection connection;
int count = 0;
PreparedStatement preparedStatement;
ResultSet resultSet; connection = JDBCTools.getConnection();
try {
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery(); if (resultSet.next()) {
count = resultSet.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}
return count;
}
}
以上是上一周学习的一部分,剩下的我很快就会发布,希望大家提出自己宝贵的意见,谢谢!
JDBC(MySQL)一周学习总结(一)的更多相关文章
- JDBC(MySQL)一周学习总结(二)
上一篇文章我们总结了获取数据库连接以及操作数据表的一些知识点,本篇将继续上次的文章给大家分享! 1. 上一篇文章我们可以对数据表进行增删改查的操作了,对与一些小项目的部分功能我们也足以胜任.但现在有一 ...
- JDBC+MYSQL初始学习
JDBC+MYSQL初始学习 一.学习准备 Eclipse 开发工具 + mysql数据库+navicat 数据库连接工具 Mysql的数据库连接驱动jar包 + testing测试集成+mave ...
- JDBC MYSQL 学习笔记(一) JDBC 基本使用
1.JDBC简单介绍 SUN公司为了简化.统一对数据库的操作,定义了一套Java操作数据库的规范.称之为JDBC. JDBC全称为:Java Data Base Connectivity(java数据 ...
- 20145212 《Java程序设计》第9周学习总结
20145212 <Java程序设计>第9周学习总结 教材学习内容总结 一.JDBC架构 1.数据库驱动 这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插 ...
- 20145213《Java程序设计》第九周学习总结
20145213<Java程序设计>第九周学习总结 教材学习总结 "五一"假期过得太快,就像龙卷风.没有一点点防备,就与Java博客撞个满怀.在这个普天同庆的节日里,根 ...
- 20145206《Java程序设计》第9周学习总结
20145206 <Java程序设计>第9周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC是用于执行SQL的解决方案,开发人员使用JDBC的标准接口,数据库厂商则对接口进行操作 ...
- 20145223《Java程序程序设计》第9周学习总结
20145223<Java程序设计>第9周学习总结 教材学习内容总结 第十六章:整合数据库 JDBC入门 1.JDBC简介: 2.JDBC主要分成两个部分,JDBC应用程序开发者接口和JD ...
- 21045308刘昊阳 《Java程序设计》第九周学习总结
21045308刘昊阳 <Java程序设计>第九周学习总结 教材学习内容总结 第16章 整合数据库 16.1 JDBC入门 16.1.1 JDBC简介 数据库本身是个独立运行的应用程序 撰 ...
- # 20145334 《Java程序设计》第9周学习总结
20145334 <Java程序设计>第9周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC 1.Java语言访问数据库的一种规范,是一套API. 2.JDBC (Java Da ...
随机推荐
- Azure Powershell使用已有Image创建ARM非托管磁盘虚拟机
生成Image映像文件,记录好Image的URL(下面URL为测试URL,具体请参考实际):ImageURL:https://hlmrgstoragen.blob.core.chinacloudapi ...
- ThinkPHP中:用户登录权限验证类
使用CommonAction.class.php公共类,统一判断用户是否登录 <?php //后台登录页 Class CommonAction extends Action{ //后台登录页面 ...
- 实例讲解webpack的基本使用第一篇
更新文章不容易,尤其是更新高质量的文章更加不易,因此为了节约时间,闲话就不多说了.关于webpack的介绍,webpack是用来干嘛的,这些基础概念性的东西,就不在此赘述,下面直接开始正题. webp ...
- Elevator poj3539
Elevator Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 1072 Accepted: 287 Case Time ...
- 笨鸟先飞之ASP.NET MVC系列之过滤器(02授权过滤器)
授权过滤器 概念介绍 在之前的文章中我们已经带大家简单的了解了下过滤器,本次我们开始介绍授权过滤器. 我们之前提到过授权过滤器在认证过滤器之后,其他过滤器和方法被调用之前运行,而授权过滤器和它名字的含 ...
- webpack2使用ch4-向根目录index.html文件传参并使用参数 使用线上资源 压缩html
1 webpack.config.js const webpack = require('webpack'), htmlWebpackPlugin = require('html-webpack-pl ...
- HDU1223 Order Count 动态规划 组合数
动态规划+组合数+大数 #include<cstdio> #include<cstdlib> #include<iostream> #include<algo ...
- Linux-fdisk磁盘分区命令(16)
名称: fdisk 使用: fdisk [块设备磁盘] 说明: 将一个块设备(磁盘)分成若干个块设备(磁盘),并将分区的信息写进分区表. fdisk命令菜单常用参数如下所示: d:(del)删除一个 ...
- wpf值转换器IValueConverter例子
转载:http://blog.163.com/wangzhenguo2005@126/blog/static/37140526201085113430862/ 值转换器可以把一种类型转换成另一种类型. ...
- 配合JdbcUtils最终版重写QueryRunner
在使用QueryRunner类的时候,直接new本类,无需传递连接池或连接,如果是普通连接,最终释放连接 /** * * 在使用QueryRunner类的时候,直接new本类,无需传递连接池或连接 * ...