网游活动情报网 - 新服预约与福利指南

Java——数据库编程JDBC之快速入门吐血总结及各关键对象详解(提供了JDBCUtils工具类)

1 JDBC基本概念JDBC,Java Database Connectivity,Java数据库连接,Java语言操作数据库。JDBC的本质是SUN公司定义的一套操作所有关系型数据库的规则,即接口,各数据库厂商实现这套接口,提供数据库驱动jar包,用户可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

2 JDBC的快速入门使用JDBC的步骤:

1)导入驱动jar包:mysql-connector-java-5.1.37-bin.jar;

-- 复制jar包到项目的libs目录下;

-- 右键,Add As Library;2)编写代码,注册驱动;3)获取数据库的连接对象;4)定义sql语句;5)获取执行sql语句的对象statement;6)执行sql,接收返回结果;7)处理结果;8)释放资源,否则可能会造成内存的泄露问题。快速入门代码如下:

代码语言:javascript复制public class JdbcDemo1 {

public static void main(String[] args) throws Exception {

//1)导入驱动jar包

//2)注册驱动

Class.forName("com.mysql.jdbc.Driver");

//3)获取数据库连接对象

Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","root");

//4)定义sql语句

String sql = "update account set balance = 500 where id = 2";

//5)获取执行sql的对象Statement

Statement statement = connection.createStatement();

//6)执行sql

int count = statement.executeUpdate(sql);

//7)处理结果

System.out.println(count);

//8)释放资源

statement.close();

connection.close();

}

}3 JDBC各对象详解3.1 DriverManager驱动管理对象1)注册驱动:告诉程序该使用哪一个数据库驱动jar

static void registerDriver(Driver driver),注册与给定的驱动程序DriverManager,但是写代码时使用的是Class.forName("com.mysql.jdbc.Driver"),为什么?查看源码发现,在com.mysql.jdbc.Driver类中存在静态代码块:

【注意】:实际上mysql5以后的驱动jar包可以省略注册驱动的步骤,若没有写,程序会读取下面的文件实现自动注册,但是,实际开发中还是写上,避免有误区;

2)获取数据库连接

方法:public static java.sql.Connection getConnection(String url, String user, String password);

参数:url:指定连接的路径,写法:jdbc:mysql://ip地址(域名):端口号/数据库名称;

user:用户名

password:密码

【注意】:若连接是本机的mysql服务器,且mysql默认端口是3306,则url可以简写为jdbc:mysql:///数据库名称;

3.2 Connection数据库连接对象1)获取执行sql的对象

Statement createStatement()PreparedStatement prepareStatement(String sql)2)管理事务

开启事务:setAutoCommit(boolean autoCommit):设置参数为false,即开启事务;提交事务:commit();回滚事务:rollback();3.3 Statement执行SQL的对象1)执行sql

boolean execute(String sql):执行给定的sql语句,返回可能的结果(了解即可,不常用)。int executeUpdate(String sql):执行DML(insert、update、delete)语句、DDL(create、alter、drop)语句。

返回值:影响的行数,可以通过这个结果判断DML语句是否执行成功,返回值>0则成功,反之则失败。ResultSet executeQuery(String sql):执行DQL(select)语句。【举例】:在account表中添加一条记录、修改记录、删除一条记录,要考虑异常处理及资源释放的规范性。

代码语言:javascript复制public class JdbcDemo2 {

public static void main(String[] args) {

Connection connection = null;

Statement statement = null;

try {

//1、注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2、定义sql

String sql = "insert into account values(null,'wangsan',2000)";

//3、获取Connection对象

connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root");

//4、获取执行sql对象

statement = connection.createStatement();

//5、执行sql

int cnt = statement.executeUpdate(sql);

//6、处理结果

System.out.println(cnt);

if(cnt>0){

System.out.println("添加成功");

}else{

System.out.println("添加失败");

}

} catch (ClassNotFoundException | SQLException e) {

e.printStackTrace();

}finally {

//7、释放资源

//要避免空指针异常

if(statement!=null){

try {

statement.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if(connection!=null){

try {

connection.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

}

}以上程序为添加一条记录,修改、删除记录与其相似,只需要改下sql语句:

修改:String sql = "update account set balance = 1500 where id =3";删除:String sql = "delete from account where id =3";3.4 ResultSet结果集对象Statement的executeQuery方法,返回的就是ResultSet结果集对象,用户需要做的就是把结果从ResultSet中取出来,涉及到两类方法:

next()方法:游标向下移动一行(游标默认是在表头处),判断当前行是否是最后一行之后(是否有数据),若是,则返回false,否则返回true;getXxx(参数)方法:获取一列的数据;

Xxx代表数据类型,如String getString();

参数:Int,代表列的编号,从1 开始,如getString(1);

String,代表列的名称,如getDouble("balance");3.4.1 ResultSet的基本使用代码语言:javascript复制public class JdbcDemo3 {

public static void main(String[] args) {

Connection connection = null;

Statement statement = null;

ResultSet resultSet = null;

try {

//1、注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2、定义sql

String sql = "select * from account";

//3、获取Connection对象

connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root");

//4、获取执行sql对象

statement = connection.createStatement();

//5、执行sql

resultSet = statement.executeQuery(sql);

//6、处理结果

//6.1 先让游标向下移动一行

resultSet.next();

int id = resultSet.getInt(1);

String name = resultSet.getString("name");

double balance = resultSet.getDouble(3);

System.out.println(id+ "--"+ "name"+"--"+balance);

} catch (ClassNotFoundException | SQLException e) {

e.printStackTrace();

}finally {

//7、释放资源

//要避免空指针异常

if(resultSet!=null){

try {

resultSet.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if(statement!=null){

try {

statement.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if(connection!=null){

try {

connection.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

}

}以上只是ResultSet的基本使用,前提是我们知道表中的有几条数据,但实际查询中我们不能确定查询到的结果是多少条,有存在游标超限等异常可能。

【注意使用步骤】:

1)游标向下移动一行;2)判断是否有数据(仍使用next()方法);3)获取数据;所以,将以上代码中,处理结果的语句改进如下:

代码语言:javascript复制 //6、处理结果

//6.1 先让游标向下移动一行

while(resultSet.next()){

int id = resultSet.getInt(1);

String name = resultSet.getString("name");

double balance = resultSet.getDouble(3);

System.out.println(id+ "--"+ "name"+"--"+balance);

}3.4.2 ResultSet进阶练习(查询的数据封装为对象)【要求】:查询emp表中的数据,将其封装为对象,然后装载集合返回。

【实现思路】:

1)定义Emp类;2)定义方法public List findAll(){}3)实现方法:select * from emp;【源码】:其中,可以以findAll方法为模板,封装个自己的mysql的查询工具类

1)JdbcDemo.java

代码语言:javascript复制public class JdbcDemo4 {

public static void main(String[] args) {

//测试

List list = new JdbcDemo4().findAll();

System.out.println(list.size());

System.out.println(list);

}

public List findAll(){

Connection connection = null;

Statement statement = null;

ResultSet resultSet = null;

List list = null;

try {

//1、注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2、定义sql

String sql = "select * from emp";

//3、获取Connection对象

connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root");

//4、获取执行sql对象

statement = connection.createStatement();

//5、执行sql

resultSet = statement.executeQuery(sql);

//6、处理结果

//遍历结果集,封装对象,装载集合

Emp emp = null;

list = new ArrayList<>();

while(resultSet.next()){

int id = resultSet.getInt("id");

String name = resultSet.getString("name");

String gender = resultSet.getString("gender");

double salary = resultSet.getDouble("salary");

Date date = resultSet.getDate("join_date");

int dept_id = resultSet.getInt("dept_id");

emp = new Emp();

emp.setId(id);

emp.setName(name);

emp.setGender(gender);

emp.setSalary(salary);

emp.setJoin_date(date);

emp.setDept_id(dept_id);

list.add(emp);

}

} catch (ClassNotFoundException | SQLException e) {

e.printStackTrace();

}finally {

//7、释放资源

//要避免空指针异常

if(resultSet!=null){

try {

resultSet.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if(statement!=null){

try {

statement.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if(connection!=null){

try {

connection.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

return list;

}

}2)Emp.java 类

代码语言:javascript复制public class Emp {

private int id;

private String name;

private String gender;

private Double salary;

private Date join_date;

private int dept_id;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getGender() {

return gender;

}

public void setGender(String gender) {

this.gender = gender;

}

public Double getSalary() {

return salary;

}

public void setSalary(Double salary) {

this.salary = salary;

}

public Date getJoin_date() {

return join_date;

}

public void setJoin_date(Date join_date) {

this.join_date = join_date;

}

public int getDept_id() {

return dept_id;

}

public void setDept_id(int dept_id) {

this.dept_id = dept_id;

}

@Override

public String toString() {

return "Emp{" +

"id=" + id +

", name='" + name + '\'' +

", gender='" + gender + '\'' +

", salary=" + salary +

", joindate=" + join_date +

", dept_id=" + dept_id +

'}';

}

}3.4.3 抽取JdbcUtils工具类由上一节我们可以发现,完成JDBC操作时,代码重复度特别高,每一次操作都要获取连接----释放资源,所以可以写一个工具类,来简化代码书写:

抽取一个方法注册驱动;抽取一个方法获取连接对象;

需求:不传递参数,比较麻烦,还得保证工具类的通用性;

解决:通过配置文件解决此问题,提供一个文件jdbc.properties,定义url=...,user=...,password=...,读取配置文件即可获取参数,参数发生变化时只需该配置文件,无需改动代码。抽取一个方法释放资源【JdbcUtils工具类源码】

代码语言:javascript复制//JDBC工具类

public class JdbcUtils {

private static String url;

private static String user;

private static String password;

private static String driver;

/**

* 文件的读取只需要读取一次

* */

static {

//读取资源文件,获取值

try {

//1、创建Properties

Properties pro = new Properties();

//2、加载文件

//动态获取src路径下的文件的方式 类加载器

ClassLoader loader = JdbcUtils.class.getClassLoader();

URL resource = loader.getResource("jdbc.properties");

String path = resource.getPath();

pro.load(new FileReader(path));

//3、获取属性赋值

url = pro.getProperty("url");

user = pro.getProperty("user");

password = pro.getProperty("password");

driver = pro.getProperty("driver");

//4、注册驱动

Class.forName(driver);

} catch (IOException | ClassNotFoundException e) {

e.printStackTrace();

}

}

/*

* 获取连接

*

* */

public static Connection getConnection() throws SQLException{

return DriverManager.getConnection(url,user,password);

}

/*

* 释放资源

*

* */

public static void close(Statement stmt,Connection conn){

if(stmt!=null){

try {

stmt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if(conn!=null){

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

/*

* 释放资源

*

* */

public static void close(ResultSet rs, Statement stmt, Connection conn){

if(rs!=null){

try {

rs.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if(stmt!=null){

try {

stmt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if(conn!=null){

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}【举例】:通过键盘录入用户名及密码,判断用户登录成功或失败

1)先准备user数据库表

代码语言:javascript复制CREATE TABLE USER(

id INT PRIMARY KEY AUTO_INCREMENT,

NAME VARCHAR(20),

psd VARCHAR(20)

);

INSERT INTO USER VALUES(NULL,'zhangsan','123');

INSERT INTO USER VALUES(NULL,'lisi','456');

SELECT * FROM USER;2)登录方法 代码及测试

代码语言:javascript复制public class JdbcDemo6 {

public static void main(String[] args) {

//键盘输入

Scanner scanner = new Scanner(System.in);

System.out.println("请输入用户名:");

String usr = scanner.nextLine();

System.out.println("请输入密码:");

String psd = scanner.nextLine();

//登录验证

Boolean b = login(usr,psd);

if(b){

System.out.println("登录OK");

}else{

System.out.println("登录fail");

}

}

public static boolean login(String user,String psd){

Connection connection = null;

Statement statement = null;

ResultSet resultSet = null;

if(user == null || psd == null){

return false;

}

try {

connection = JdbcUtils.getConnection();

String sql = "select * from user where name = '"+user+"' and psd = '"+psd+"' ";

statement = connection.createStatement();

resultSet = statement.executeQuery(sql);

return resultSet.next();

} catch (SQLException throwables) {

throwables.printStackTrace();

}finally {

JdbcUtils.close(resultSet,statement,connection);

}

return false;

}

}3.5 PreparedStatement执行SQL的对象1)SQL注入问题:在拼接sql时,有一些特殊的关键字参与字符的拼接,会造成安全性问题。

以上登录验证,实际上没有这么干的,因为质量太差,我们试验下,输入如下用户名及密码,看下结果如何:

随便输入的用户名和密码,竟然也登录成功了。以上的问题就是SQL注入问题,看打印出的sql语句,or 'a' = 'a',这是个恒等式,所以才会出现上述的问题。

2)解决SQL注入问题:使用PreparedStatement对象

预编译SQL:参数使用?作为占位符

使用步骤:

1)导入驱动jar包:mysql-connector-java-5.1.37-bin.jar;2)编写代码,注册驱动;3)获取数据库的连接对象;4)定义sql语句;

注意:sql的参数使用?作为占位符,如select * from user where user= ? and psd = ?;5)获取执行sql语句的对象PreparedStatement,Connection.prepareStatement(String sql);6)给?赋值,使用PreparedStatement中的方法,setXxx(参数1,参数2);参数1 :?位置,从1 开始,参数2:?的值;7)执行sql(不需要传递sql语句),接收返回结果;8)处理结果;9)释放资源,否则可能会造成内存的泄露问题。【注意】:后期都会使用PrepareStatement对象完成增删改查的所有操作,可以防止SQL注入,且效率更高,不会再用Statement对象。

使用PrepareStatement完成上述的 登录验证案例如下:

代码语言:javascript复制public static boolean login2(String user,String psd){

Connection connection = null;

PreparedStatement statement = null;

ResultSet resultSet = null;

if(user == null || psd == null){

return false;

}

try {

connection = JdbcUtils.getConnection();

String sql = "select * from user where name = ? and psd = ? ";

// System.out.println(sql);

statement = connection.prepareStatement(sql);

//给?赋值

statement.setString(1,user);

statement.setString(2,psd);

resultSet = statement.executeQuery();

return resultSet.next();

} catch (SQLException throwables) {

throwables.printStackTrace();

}finally {

JdbcUtils.close(resultSet,statement,connection);

}

return false;

}4 JDBC事务管理关于事务可以看下这篇博客,使用JDBC控制事务,需要使用Connection对象来管理事务:

开启事务:setAutoCommit(boolean autoCommit),调用方法时参数为false,在执行sql之前开启事务;提交事务:commit(),当所有sql都执行完提交事务;回滚事务:rollback(),在catch中回滚事务。【举例】:使用JDBC进行事务管理的示例,zhangsan -500,lisi +500,注意何时开启事务,何时提交事务,何时回滚事务。

代码语言:javascript复制public class JdbcDemo7 {

public static void main(String[] args) {

Connection connection = null;

PreparedStatement pstmt1 = null;

PreparedStatement pstmt2 = null;

try {

//1、获取连接

connection = JdbcUtils.getConnection();

connection.setAutoCommit(false);//开启事务

//2、定义sql

String sql1 = "update account set balance = balance - ? where id = ?";

String sql2 = "update account set balance = balance + ? where id = ?";

//3、获取执行sql对象

pstmt1 = connection.prepareStatement(sql1);

pstmt2 = connection.prepareStatement(sql2);

//4、设置参数

pstmt1.setDouble(1,500);

pstmt1.setInt(2,1);

pstmt2.setDouble(1,500);

pstmt2.setInt(2,2);

//5、执行sql

pstmt1.executeUpdate();

//手动制造异常

int i = 3/0;

pstmt2.executeUpdate();

connection.commit(); //提交事务

} catch (Exception e) {

try {

if(connection != null){

connection.rollback();//事务回滚

}

} catch (SQLException throwables) {

throwables.printStackTrace();

}

e.printStackTrace();

}finally {

JdbcUtils.close(pstmt1,connection);

JdbcUtils.close(pstmt2,null);

}

}

}———————————————————————————————————————

本文为博主原创文章,转载请注明出处!