JAVA Database Connectivity java 数据库连接
SUN公司提供的一种数据库访问规则、规范, 由于数据库种类较多,并且java语言使用比较广泛,sun公司就提供了一种规范,让其他的数据库提供商去实现底层的访问规则。 我们的java程序只要使用sun公司提供的jdbc驱动即可。
导入属于java提供的和数据库无关的类
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
导入具体数据库相关的jar包
//mysql
mysql-connector-java-5.1.7-bin.jar
//oracle
ojdbc5.jar
public static void main(String args[]) {
try {
//1.注册驱动
DriverManager.registerDriver(new OracleDriver());
//2.创建连接
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@103.10.87.51:1521/myoracle", "wangcf", "wangcf");
//3.创建statement对象
Statement statement = connection.createStatement();
//4.获取结果
ResultSet resultSet = statement.executeQuery("select * from test");
while (resultSet.next()) {
System.out.println("工号:" + resultSet.getInt(1) +
"姓名:" + resultSet.getString(2));
}
} catch(SQLException e) {
e.printStackTrace();
}finally{
//5.释放资源
resultSet.close();
statement.close();
connection.close();
//JDBCUtil.release(connection, statement, resultSet);
}
}
创建一个工具类JDBCUtil
对一些共用代码进行整合
对数据库的连接可以只维护这个类文件
在资源释放时也可能发生异常,资源释放的代码需要更加严谨。
并且将释放资源的代码进行整合,方便维护。
public class JDBCUtil {
/**
* 释放资源
* @param connection
* @param statement
* @param resultSet
*/
public static void release(Connection connection, Statement statement, ResultSet resultSet) {
closeResultSet(resultSet);
closeStatement(statement);
closeConnection(connection);
}
/**
* 释放结果集资源
* @param resultSet
*/
private static void closeResultSet(ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
resultSet = null;
}
}
/**
* 释放statement资源
* @param statement
*/
private static void closeStatement(Statement statement) {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
statement = null;
}
}
/**
* 释放数据库连接资源
* @param connection
*/
private static void closeConnection(Connection connection) {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
connection = null;
}
}
}
//mysql手动注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//oracle手动注册驱动
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
但是在com.mysql.jdbc.Driver/oracle.jdbc.driver.OracleDriver这个类里面有静态代码块
//com.mysql.jdbc.Driver
java.sql.DriverManager.registerDriver(new Driver());
//oracle.jdbc.driver.OracleDriver
defaultDriver = new oracle.jdbc.OracleDriver();
DriverManager.registerDriver(defaultDriver);
该静态代码块在类加载时执行,所以等同于我们注册了两次驱动。
其实没这个必要的,最后形成以下代码,通过类加载来注册驱动
//mysql
Class.forName("com.mysql.jdbc.Driver");
//oracle
Class.forName("oracle.jdbc.driver.OracleDriver");
注意
册驱动可以省略
在jar包 的ojdbc5.jar!\META-INF\services\java.sql.Driver该文件中有
oracle.jdbc.OracleDriver
此处提供了类名
将注册驱动和获取数据库连接整合到工具类中
/**
* 获取数据库连接
* @return
*/
public static Connection getConnection() {
Connection connection = null;
try {
//通过类加载注册驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//获取数据库连接
connection = DriverManager.getConnection("jdbc:oracle:thin:@103.10.87.51:1521/myoracle", "wangcf", "wangcf");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
java提供的JDBC和数据库提供的相关类之间的关联其实就是
驱动类、URL地址,数据库账号,数据库密码这4个字符串
通过创建properties文件使其解耦
这样在更换数据库时只需要修改properties类即可
driverClass=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@103.10.87.51:1521/myoracle
name=wangcf
password=wangcf
配置文件只需要在程序启动时读取一次,所以放到静态代码块中
在类加载时就读取配置
private static String driverClass = null;
private static String url = null;
private static String name = null;
private static String password = null;
static {
try {
//创建properties配置文件对象
Properties properties = new Properties();
//使用类加载器读取src目录下的文件
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
//导入输入流
properties.load(is);
//读取属性
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
name = properties.getProperty("name");
password = properties.getProperty("password");
//释放资源
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
用到的方法
statement.executeUpdate返回受影响的行数
statement.executeQuery返回ResultSet结果集
//返回受影响的行数,期望的sql是inset、update、delete;但是写select也会有返回值
int count = statement.executeUpdate("select * from test");
System.out.println(count); //2
count = statement.executeUpdate("insert into test values (00023,'张三')");
System.out.println(count); //1
int count = statement.executeUpdate("delete from test where user_name='张三'");
//1.获取连接对象
connection = JDBCUtil.getConnection();
//3.创建statement对象
statement = connection.createStatement();
//4.获取结果
resultSet = statement.executeQuery("select * from test");
//遍历结果集
while (resultSet.next()) {
System.out.println("工号:" + resultSet.getInt(1) + ";姓名:" + resultSet.getString(2));
}
//即使被更新过,再执行还会有一行受影响
int count = statement.executeUpdate("update test set user_name='小丽' where user_id='00002'");
System.out.println(count); //1
@Test
public void testQuery() {
...
}
Data Access Object 数据访问对象
/**
* 定义操作数据库的方法
*/
public interface UserDao {
/**
* 查找全部数据
*/
void findAll();
/**
* 插入数据
*/
void insert();
}
public class UserDaoImpl implements UserDao {
@Override
public void findAll() {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1.获取连接对象
connection = JDBCUtil.getConnection();
//3.创建statement对象
statement = connection.createStatement();
//4.获取结果
resultSet = statement.executeQuery("select * from test");
//遍历结果集
while (resultSet.next()) {
System.out.println("工号:" + resultSet.getString(1) +
";姓名:" + resultSet.getString(2));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(connection, statement, resultSet);
}
}
@Override
public void insert() {
}
}
public void testFindAll() {
UserDao userDao = new UserDaoImpl();
userDao.findAll();
}
Statement执行 ,其实是拼接sql语句的
先拼接sql语句,然后在一起执行。
如果再登录时用到以下SQL语句
String sql = "select * from test where username='" + username + "' and password='" + password + "'";
并且用以下方式传值
UserDao dao = new UserDaoImpl();
userDao.login("zhangsan","1' or '1'='1");
将拼接成为如下sql语句
select * from test where username='zhangsan' and password='1' or '1'='1'
问题
前面先拼接sql语句, 如果变量里面带有了 数据库的关键字,那么一并认为是关键字,不认为是普通的字符串。
这样就导致不正确的密码也可以登录
该对象就是替换前面的statement对象。
相比较以前的statement, 预先处理给定的sql语句,对其执行语法检查。
在sql语句里面使用?
占位符来替代后续要传递进来的变量。
后面进来的变量值,将会被看成是字符串,不会产生任何的关键字。
//先定义sql语句
String sql = "select * from test where username=? and password=?";
ps = connection.prepareStatement(sql);
//占位符 从 1 开始
ps.setString(1, username);
ps.setString(2, password);
//ps.setInt();
//执行sql
resultSet = ps.executeQuery();