zl程序教程

您现在的位置是:首页 >  工具

当前栏目

JDBC学习1:详解JDBC使用编程语言

学习JDBC编程语言 使用 详解
2023-06-13 09:11:53 时间

什么是JDBC

JDBC(Java Database Connectivity),即Java数据库连接,是一种用于执行SQL语句的Java API,可以为多种关系数据库提供同一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,根据这种基准可以构建更高级的工具和接 口,使数据库开发人员能够编写数据库应用程序。总而言之,JDBC做了三件事:

1、与数据库建立连接

2、发送操作数据库的语句

3、处理结果

JDBC简单示例

下面的代码演示了如何利用JDBC从数据库中查询若干条符合要求的数据出来,使用的数据库是MySql。

1、建立一个数据库和一张表,我的习惯是在CLASSPATH底下建立一个.sql的文件用于存放sql语句


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、根据表字段建立实体类


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文件读到内存中,可以参看IT虾米网我之前写的文章的最后


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出来也没看出来会有什么好处),节省资源


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; } }
List Student studentList = new ArrayList 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 方法就要这么写:


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; }
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("添加学生信息失败"); }

运行就不运行了,反正最后结果是 添加学生信息成功 ,数据库里面多了一条数据。注意一下:

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(); } }