JDBC学习1:详解JDBC使用
什么是JDBC
JDBC(Java Database Connectivity),即Java数据库连接,是一种用于执行SQL语句的Java API,可以为多种关系数据库提供同一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,根据这种基准可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。总而言之,JDBC做了三件事:
1、与数据库建立连接
2、发送操作数据库的语句
3、处理结果
JDBC简单示例
下面的代码演示了如何利用JDBC从数据库中查询若干条符合要求的数据出来,使用的数据库是MySql。
1、建立一个数据库和一张表,我的习惯是在CLASSPATH底下建立一个.sql的文件用于存放sql语句
create database school; use school; create table student
(
studentId int primary key auto_increment not null,
studentName varchar(10) not null,
studentAge int,
studentPhone varchar(15)
) insert into student values(null,'Betty', '20', '00000000');
insert into student values(null,'Jerry', '18', '11111111');
insert into student values(null,'Betty', '21', '22222222');
insert into student values(null,'Steve', '27', '33333333');
insert into student values(null,'James', '22', '44444444');
commit;
2、建立一个.properties文件用于存储MySql连接的几个属性。为什么要建立.properties而不在代码里面写死,由于这个并不是Java设计模式的分类,就不细讲了,只需要记住:从设计的角度看,把内容写在配置文件中永远好过把内容写死在代码中。
mysqlpackage=com.mysql.jdbc.Driver
mysqlurl=jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf-8
mysqlname=root
mysqlpassword=root
3、根据表字段建立实体类
public class Student
{
private int studentId;
private String studentName;
private int studentAge;
private String studentPhone; public Student(int studentId, String studentName, int studentAge,
String studentPhone)
{
this.studentId = studentId;
this.studentName = studentName;
this.studentAge = studentAge;
this.studentPhone = studentPhone;
} public int getStudentId()
{
return studentId;
} public String getStudentName()
{
return studentName;
} public int getStudentAge()
{
return studentAge;
} public String getStudentPhone()
{
return studentPhone;
} public String toString()
{
return "studentId = " + studentId + ", studentName = " + studentName + ", studentAge = " +
studentAge + ", studentPhone = " + studentPhone;
}
}
4、写一个DBConnection类专门用于向外提供数据库连接。我这里用了MySql,所以只有一个mysqlConnection,如果还用到了Oracle,当然还可以向外提供一个oracleConnection。把这些连接设为全局的可能有人会想是否会有线程安全问题,这是一个很好的问题。那因为我们只从Connection里面读取一个PreparedStatement出来,而不会去写它,只读不修改,是不会引发线程安全问题的。另外把Connection设置为static的保证了Connection在内存中只有一份,不会占多大资源,每次使用完不调用close()方法去关闭它也没事。至于把.properties文件读到内存中,可以参看http://www.cnblogs.com/xrq730/p/4847337.html我之前写的文章的最后
public class DBConnection
{
private static Properties properties = new Properties(); static
{
/** 要从CLASSPATH下取.properties文件,因此要加"/" */
InputStream is = DBConnection.class.getResourceAsStream("/db.properties");
try
{
properties.load(is);
}
catch (IOException e)
{
e.printStackTrace();
}
} /** 这个mysqlConnection只是为了用来从里面读一个PreparedStatement,不会往里面写数据,因此没有线程安全问题,可以作为一个全局变量 */
public static Connection mysqlConnection = getConnection(); public static Connection getConnection()
{
Connection con = null;
try
{
Class.forName((String)properties.getProperty("mysqlpackage"));
con = DriverManager.getConnection((String)properties.getProperty("mysqlurl"),
(String)properties.getProperty("mysqlname"),
(String)properties.getProperty("mysqlpassword"));
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (SQLException e)
{
e.printStackTrace();
}
return con;
}
}
5、建立一个工具类,用来写各种方法,专门和数据库进行交互。这种工具类最好搞成单例的,这样就不用每次去new出来了(实际上new出来也没看出来会有什么好处),节省资源
package com.xrq.test11; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List; public class StudentManager
{
private static StudentManager instance = new StudentManager(); private StudentManager()
{ } public static StudentManager getInstance()
{
return instance;
} public List<Student> querySomeStudents(String studentName) throws Exception
{
List<Student> studentList = new ArrayList<Student>();
Connection connection = DBConnection.mysqlConnection;
PreparedStatement ps = connection.prepareStatement("select * from student where studentName = ?");
ps.setString(1, studentName);
ResultSet rs = ps.executeQuery(); Student student = null;
while (rs.next())
{
student = new Student(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getString(4));
studentList.add(student);
} ps.close();
rs.close();
return studentList;
}
}
6、写个main函数去调用一下
List<Student> studentList = StudentManager.getInstance().querySomeStudents("Betty");
for (Student student : studentList) {
System.out.println(student);
}
7、看一下运行结果,和数据库里面的一样,成功
studentId = 1, studentName = Betty, studentAge = 20, studentPhone = 00000000
studentId = 3, studentName = Betty, studentAge = 21, studentPhone = 22222222
为什么要使用占位符"?"
看一下第5点,大家一定注意到了,写sql语句的时候用了"?"占位符,当然有美化代码的因素,不用占位符就要在括号里写"+"来拼接参数,如果要拼接的参数一多,代码肯定不好看,可读性不强。但是除了这个原因,还有另外一个重要的原因,就是避免一个安全问题。假设我们不用占位符写sql语句,那"querySomeStudents(String name) throws Exception"方法就要这么写:
public List<Student> querySomeStudents(String studentName) throws Exception
{
List<Student> studentList = new ArrayList<Student>();
Connection connection = DBConnection.mysqlConnection;
PreparedStatement ps = connection.prepareStatement("select * from student where studentName = '" + studentName + "'");
ResultSet rs = ps.executeQuery(); Student student = null;
while (rs.next())
{
student = new Student(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getString(4));
studentList.add(student);
} ps.close();
rs.close();
return studentList;
}
上面的main函数一样可以获取到两条数据,但是问题来了,如果我这么调用呢:
public static void main(String[] args) throws Exception
{
List<Student> studentList = new ArrayList<Student>();
studentList = StudentManager.getInstance().querySomeStudents("' or '1' = '1");
for (Student student : studentList)
System.out.println(student);
}
看下运行结果:
studentId = 1, studentName = Betty, studentAge = 20, studentPhone = 00000000
studentId = 2, studentName = Jerry, studentAge = 18, studentPhone = 11111111
studentId = 3, studentName = Betty, studentAge = 21, studentPhone = 22222222
studentId = 4, studentName = Steve, studentAge = 27, studentPhone = 33333333
studentId = 5, studentName = James, studentAge = 22, studentPhone = 44444444
为什么?看下拼接之后的sql语句就知道了:
select * from student where studentName = '' or '1' = '1'
'1'='1'永远成立,所以前面的查询条件是什么都没用。这种问题是有应用场景的,不是随便写一下。Java越来越多的用在Web上,既然是Web,那么查询的时候有一种情况就是用户输入一个条件,后台获取到查询条件,拼接sql语句查数据库,有经验的用户完全可以输入一个"‘'' or '1' = '1",这样就拿到了库里面的所有数据了。
JDBC事物
谈数据库必然离不开事物,事物简单说就是"要么一起成功,要么一起失败"。那简单往前面的StudentManager里面写一个插入学生信息的方法:
public void addStudent(String studentName, int studentAge, String studentPhone) throws Exception
{
Connection connection = DBConnection.mysqlConnection;
PreparedStatement ps = connection.prepareStatement("insert into student values(null,?,?,?)");
ps.setString(1, studentName);
ps.setInt(2, studentAge);
ps.setString(3, studentPhone);
if (ps.executeUpdate() > 0)
System.out.println("添加学生信息成功");
else
System.out.println("添加学生信息失败");
}
public static void main(String[] args) throws Exception
{
StudentManager.getInstance().addStudent("Betty", 17, "55555555");
}
运行就不运行了,反正最后结果是"添加学生信息成功",数据库里面多了一条数据。注意一下:
1、增删改用的是executeUpdate()方法,因为增删改认为都是对数据库的更新
2、查询用的是executeQuery()方法,看名字就知道了"Query",查询嘛
可能有人注意到一个问题,就是Java代码在insert后并没有对事物进行commit,数据就添加进数据库了,也能查出来,这是为什么呢?因为JDK的Connection设置了事物的自动提交。如果在addStudent(...)方法里面这么写:
Connection connection = DBConnection.mysqlConnection;
connection.setAutoCommit(false);
autoCommit这个属性原来是true,JDK自然会帮助开发者自动提交事物了。OK,如果要改成手动提交事物的代码,那么应该这么写addStudent(...)方法:
public void addStudent(String studentName, int studentAge, String studentPhone) throws Exception
{
Connection connection = DBConnection.mysqlConnection;
connection.setAutoCommit(false);
PreparedStatement ps = connection.prepareStatement("insert into student values(null,?,?,?)");
ps.setString(1, studentName);
ps.setInt(2, studentAge);
ps.setString(3, studentPhone);
try
{
ps.executeUpdate();
connection.commit();
}
catch (Exception e)
{
e.printStackTrace();
connection.rollback();
}
}
要记得抛异常的时候利用rollback()方法回滚掉事物。
JDBC学习1:详解JDBC使用的更多相关文章
- 详解JDBC与Hibernate区别
详解JDBC与Hibernate区别 引用地址:http://www.cnblogs.com/JemBai/archive/2011/04/13/2014940.html 刚开始学习JAVA时,认为H ...
- 执行对象Statement、PreparedStatement和CallableStatement详解 JDBC简介(五)
执行对象是SQL的执行者,SQL是“安排好的任务”,执行对象就是“实际工作的人”. 执行对象有三种: Statement.PreparedStatement和CallableStatement,他们都 ...
- mysql:JDBC url 参数详解
MySql链接url参数详解 jdbc:mysql://[host:port],[host:port].../[database][?参数名1][=参数值1][&参数名2][=参数值2]... ...
- iPhone应用开发 UITableView学习点滴详解
iPhone应用开发 UITableView学习点滴详解是本文要介绍的内容,内容不多,主要是以代码实现UITableView的学习点滴,我们来看内容. -.建立 UITableView DataTab ...
- Eclipse IDE for C/C++ Developers和MinGW安装配置C/C++开发学习环境详解
Eclipse IDE for C/C++ Developers和MinGW安装配置C/C++开发学习环境详解 操作系统:Windows 7 JDK版本:1.6.0_33 Eclipse版本:Juno ...
- JDBC常用接口详解
JDBC中常用接口详解 ***DriverManager 第一.注册驱动 第一种方式:DriverManager.registerDriver(new com.mysql.jdbc.Driver()) ...
- Jmeter系列(29)- 详解 JDBC Connection Configuration
如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 前言 发起 jdbc 请求前,需要有 ...
- 详解JDBC连接数据库
一.概念 1. 为了能让程序操作数据库,对数据库中的表进行操作,每一种数据库都会提供一套连接和操作该数据库的驱动,而且每种数据库的驱动都各不相同,例如mysql数据库使用mysql驱动,oracle数 ...
- Java jdbc 操作数据库详解
原文地址https://www.cnblogs.com/huguodong/p/5910859.html JDBC(Java Data Base Connectivity,java数据库连接)是一种用 ...
- 详解JDBC对象
1. DriverManager (1) 注册驱动 Class.forName("com.mysql.cj.jdbc.Driver"); 真正注册驱动的是驱动包下 jdbc 文件夹 ...
随机推荐
- softmax分类器+cross entropy损失函数的求导
softmax是logisitic regression在多酚类问题上的推广,\(W=[w_1,w_2,...,w_c]\)为各个类的权重因子,\(b\)为各类的门槛值.不要想象成超平面,否则很难理解 ...
- 关于 Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause() 错误
最近在做项目的时候发现一个如题的控制台报错. 一看右侧的报错文件是undefined 这下苦恼了,定位不到问题所在. 今天解决了这个问题,就来分享一下. 问题的关键所在是在执行了play()方法以后立 ...
- Jfinal连接SQLSERVER相关配置说明
driver=net.sourceforge.jtds.jdbc.Driver jdbcUrl = jdbc:sqlserver://localhost:1433;DatabaseName=test ...
- 遇到的sql关键字
select count(1) 相当于 select count(*) 网上有比较差别的 菜鸟不用管
- 大前端学习笔记整理【六】this关键字详解
前言 在上一篇博客里我总结了下辨认this指向的四种方式,但是有师兄抛出一个问题来,我发现那些this的指向并不能说明更复杂的情况,先看下这段代码 var a = { name: 'a', getNa ...
- JS中this关键字详解
本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 阅读此文章,还需要心平气和的阅读完,相信一定会有所收获,我也会不定期的发布,分享一些文章,共同学习 首先,必须搞清楚在JS里面,函数 ...
- Kiwi iOS驱动测试开发
Kiwi是iOS开发一个行为驱动开发库.目标是提供一个BDD库,精美的简单安装和使用. 安装 使用CocoaPods安装: pod 'Kiwi'如果使用Xcode5则使用: pod 'Kiwi/XCT ...
- 扩大a标签的响应区域
<a href="" style="display:inline-block; width: 100%;">xx</a>
- 如何防止JAVA反射对单例类的攻击?
在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...
- 自动挂载文件/etc/fstab功能详解
今天看了这篇文章,对于自动挂载中的一些小细节和参数有了更深的理解,所以这次把它摘下来,留做查询 一./etc/fstab文件的作用 1.我们把磁盘手动挂载之后如果不把它写入/etc/fstab这个文件 ...