JDBC(Java Data Base Connection) java数据库连接 是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一的访问,是由一组Java语言编写的类和接口,JDBC提供了一种基准,以此可以构建更高级的工具和接口。
之前我们简单讲了数据库的一些知识,我们利用驱动程序简介管理数据库。就是因为我们安装好数据库后,我们的应用程序也是不能直接使用数据库的,必须通过响应的数据库驱动程序,通过驱动程序去和数据库打交道,其实也就是数据库的厂商的JDBC接口的实现。
今天我们简单说一下,Java连接数据库的一些步骤。
首先加载mysql驱动
这里边的路径是固定的,是由mysql厂家提供的驱动去找接口。
Class.forName("com.mysql.jdbc.Driver");
有了驱动,找接口。
加载connection接口
getConnection后三个参数:
- 连接字符串 :jdbc:mysql://(ip地址/localhost本机):(数据库端口号)/数据库名称
- 数据库账号
- 数据库密码
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
整体代码如下,连接成功就会输出:连接成功。然后我们再去查询、更新数据。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
//连接数据库
public class Demo1 {
public static void main(String[] args) {
Connection connection = null;
try {
//加载mysql驱动
Class.forName("com.mysql.jdbc.Driver");
//加载connection接口 getConnection(连接字符串,数据库账号,数据库密码);
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
System.out.println("连接成功");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
//关闭连接
if (null != connection)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
注意:连接数据库操作完,要关闭连接!!!
这里有个问题,我们要导入的jar包,需要自己下载,javav本身不提供。
mysql-connector-java-5.1.0-bin.jar,就是mysql提供的jar包,网上很多,自己找找。
然后我们来操作数据。
通过Connection 的 createStatement()方法 获取Statement接口
Statement statement = connection.createStatement();
定义SQL 语句
String sql = "UPDATE student SET Phone = '15229975743' WHERE StudentNo = '1010'";
statement接口的executeUpdate()方法传入操作语句,返回影响成功的行数
int row = statement.executeUpdate(sql);
具体代码如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
//执行修改语句,返回成功影响行数
public class Demo3 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
System.out.println("连接成功");
statement = connection.createStatement();
String sql = "UPDATE student SET Phone = '15229975743' WHERE StudentNo = '1010'";
int row = statement.executeUpdate(sql);
System.out.println(row != 0?"修改成功":"修改失败");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (statement != null){
statement.close();
}
if (connection != null ){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
注意: 还是一样的,用完即关。而且是正着用倒着关,这很好理解。
然后是查询语句,查询语句不一样的是用的statement接口的executeQuery()方法,照样传入查询语句,但是返回的是一个结果集合ResultSet。
ResultSet rs = statement.executeQuery(sql);
这个集合同样的在最后用完要关掉。
这里我们说一下,查询和更新是都要传入sql语句,而有的人会利用这个去注入恶意代码,常见的sql注入,使得躲避掉数据库操作权限限制。
最简单的举个例子,我们要求用户名密码都一致,才能查询自己的成绩,sql语句:
select * from student WHERE studentUser = '李四' AND loginPwd = '123456789'
我并不知道李四的密码,甚至不知道李四的用户名,那我要查询这个数据库的信息,怎么办,我想了个办法,输入这个句子:
select * from student WHERE studentUser = '' or 1=1 -- 'AND loginPwd = ''
我们可以看到,我利用(’ or 1=1 – )构造了一个1=1的永真条件,后边直接被注释掉,那数据库那边收到这样的语句条件判断肯定为真,那我前边要查的肯定也可以查到。
那么,mysql厂商肯定也注意到这种情况,所以为connection接口提供了prepareStatement()方法。
之前我们要先利用connection接口的createStatement()方法获取statement接口,然后定义sql语句,在查询或者更新数据时用statement接口的executeQuery(sql)或executeUpdate(sql)方法去传入sql语句,进行操作,有被sql注入的风险。
现在我们利用connection接口的prepareStatement()方法去获取preparedStatement接口,它和statement接口有相同的功能,但是会预编译,而且prepareStatement()方法强制先传入sql语句进行预编译。
String sql = "select * from student WHERE studentNo = ? AND loginPwd = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"1010");
preparedStatement.setString(2,"123456");
这里我们传入的sql语句中先不传值,而是用英文的?代替,叫做占位符,
在下边用preparedStatement的(set+数据类型)方法去给占位符赋值,先说明第几个占位符,再写值为多少。
他就会利用预编译将几个值分别去验证,而不是将整个语句打包去执行。
import java.sql.*;
//利用 prepareStatement获取Statement可以预编译,防止sql注入
public class Demo4 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
System.out.println("连接成功");
String sql = "select * from student WHERE studentNo = ? AND loginPwd = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"1010");
preparedStatement.setString(2,"123456");
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
System.out.println(resultSet.getInt("studentno")+"---"+resultSet.getString("studentname"));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (resultSet != null){
resultSet.close();
}
if (preparedStatement != null){
preparedStatement.close();
}
if (connection != null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上面我们讲了用java连接mysql数据库后进行查询、更新数据的方法,但是用着不是很方便,而且我们Java讲究数据作为对象去使用。我们只是查到数据、更新数据,而没有把它弄成一个对象去操作他,没什么意义。所以,我写了下面的工具类,可以查数据、更新数据、把数据封装为一个类,然后去操作他。
import org.apache.commons.beanutils.BeanUtils;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class BaseDao {
private static Connection connection = null;
private static PreparedStatement preparedStatement = null;
private static ResultSet resultSet = null;
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void getConnection() throws SQLException {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool", "root", "root");
}
public static int executeUpdate(Object[] objects, String sql) {
int row = 0;
try {
getConnection();
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement(sql);
if (objects != null) {
for (int i = 0; i < objects.length; i++) {
preparedStatement.setObject(i + 1, objects[i]);
}
}
row = preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
try {
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} finally {
try {
connection.commit();
connection.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
closeAll();
}
return row;
}
public static ResultSet executeQuery(Object[] objects,String sql){
try {
getConnection();
preparedStatement = connection.prepareStatement(sql);
if (null != objects){
for (int i = 0; i < objects.length; i++) {
preparedStatement.setObject(i+1,objects[i]);
}
}
resultSet = preparedStatement.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return resultSet;
}
public static <T> List<T> executeQuery2(Object[] objects,String sql,Class<T> tClass){
List<T> list = new ArrayList<>();
try {
getConnection();
preparedStatement = connection.prepareStatement(sql);
if (null != objects){
for (int i = 0; i < objects.length; i++) {
preparedStatement.setObject(i+1,objects[i]);
}
}
resultSet = preparedStatement.executeQuery();
//创建集合 获取此 ResultSet 对象的列的编号、类型和属性。
// 返回:此 ResultSet 对象的列的描述
ResultSetMetaData metaData = resultSet.getMetaData();
while (resultSet.next()){
T obj = tClass.newInstance();
for (int i = 0; i < metaData.getColumnCount(); i++) {
// 获取列名 根据下标(从1开始)
String colName = metaData.getColumnName(i+1);
// 根据列名 获取 值
Object value = resultSet.getObject(colName);
//利用BeanUtils工具栏,创建对象
BeanUtils.setProperty(obj,colName,value);
}
//将组装后的结果 保存到list中
list.add(obj);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
closeAll();
}
return list;
}
public static void closeAll() {
try {
if(null != resultSet)
resultSet.close();
if(null != preparedStatement)
preparedStatement.close();
if(null != connection)
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
我们利用数据库中的属性名、值去包装类主要是利用BeanUtils工具类,他也需要导jar包。commons-beanutils-1.9.3 jar
再来一个测试类测一下工具是否好用:
import org.westos.demo.BaseDao;
import org.westos.entity.Student;
import java.util.List;
public class Test {
public static void main(String[] args) {
String sql = "select * from student WHERE studentNo = ? AND loginPwd = ? ";
Object[] objects = {1011,"123456"};
List<Student> studentList = BaseDao.executeQuery2(objects,sql,Student.class);
for (Student student : studentList) {
System.out.println(student.getStudentname());
}
}
}
我们可以看到,有了工具类后,我们只需要输入sql语句以及条件值就可以,他会创建好对象给我们,我们有一个集合去收就可以。再取数据用就可以后用我们java熟悉的get/set方法就ok。
我之前遇到包装对象出错问题,你要先确定你的属性名、数据类型和你的数据库中是一致的,然后还是出错可能因为beanutils1.9.3的包太高级,利用Fasthashmap创建对象,有的Java版本低可能会失败,所以需要找1.8的beanutils包就可以了。
好了,本次分享就到这里,希望对你有帮助,有问题请批评指正,谢谢!