数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型、XML、二进制流等。
数据存储状态一:瞬时状态
数据存储状态二:持久状态
Hibernate、JPA、JDBC(Java Datebase Connectivity)等
java.sql.Driver
接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商进行实现,不同数据库厂商提供不同的实现java.sql.DriverManager
)**去调用这些Driver实现oracle.jdbc.driver.OracleDriver
com.mysql.jdbc.Driver
(mysql6-)、com.mysql.cj.jdbc.Driver
(mysql6+)Connection conn = null;
Statement st=null;
ResultSet rs = null;
try {
//获得Connection
//创建Statement
//处理查询结果ResultSet
}catch(Exception e){
e.printStackTrance();
} finally {
//释放资源ResultSet,Statement,Connection
}
1、在项目中创建lib文件夹
2、将驱动jar文件放置到lib文件夹
3、集成到项目ClassPath中,右键build
(eclipse)、add as library
(idea)
将com.mysql.jdbc
包下的Driver类的字节码文件从本地磁盘加载到方法区中
方式一:加载 JDBC 驱动需调用 Class 类的静态方法forName()
,向其传递要加载的 JDBC 驱动的类名
//将com.mysql.jdbc包下的Driver类的字节码文件从本地磁盘加载到方法区中
Class.forname("com.mysql.jdbc.Driver")
方式二:DriverManager 类是驱动程序管理器类,负责管理驱动程序(不推荐)
DriverManager.registerDriver(com.mysql.jdbc.Driver);
通常不用显式调用 DriverManager 类的registerDriver()
方法来注册驱动程序类的实例,原因如下:
1、该方法,过于依赖jar包的存在
2、该方法,会造成二次注册
3、使用Class.forname
可以降低耦合性
//本机IP:localhost 本机端口号:3306
String url = "jdbc:mysql://ip:port/databasename?serverTimezone=Asia/Shanghai&characterEncoding=utf-8";
String user = "username";
String passWord = "password";
Connection conn = DriverManager.getConnection(url,user,passWord);
协议:JDBC URL中的协议总是jdbc
子协议:子协议用于标识一个数据库驱动程序
子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为 了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名
jdbc:mysql://<ip>:<port>/<database_name>?<key>=<value>
,常用的连接配置如下
KEY | VALUE | Description |
---|---|---|
serverTimezone | Asia/Shanghai | 时区 |
useSSL | true、false | 是否使用ssl加密连接 |
connectTimeout | 10 | 设置连接超时时间,单位是秒 |
socketTimeout | 30 | 设置读取结果集的超时时间,单位是秒 |
authenticationPlugins | mysql_native_password、sha256_password | 安全认证方式 |
characterEncoding | uft8 | 数据库字符集 |
rewriteBatchedStatements | true、false | 批量执行sql |
zeroDateTimeBehavior | EXCEPTION默认抛出异常(Zero date value prohibited)、CONVERT_TO_NULL转换为null;ROUND替换成最近的日期即0001-01-01 |
对于零值timestamp类型的处理方式 |
autoReconnect | true、false | 数据库连接中断是否重连 |
maxReconnects | 3 | 重新连接尝试次数 |
initialTimeout | 2 | 两次重连间隔时间,单位是秒 |
failOverReadOnly | true、false | 是否使用针对数据库连接池的重连策略 |
useUnicode | true、false | 是否使用Unicode字符集,如果参数characterEncoding 设置为gb2312 或gbk ,本参数值必须设置为true |
jdbc:oracle:thin:@<ip>:<port>:<database_name>?<key>=<value>
jdbc:microsoft:sqlserver//<ip>:<port>;DatabaseName=<database_name>
jdbc:postgresql://<ip>:<port>/<database_name>?<key>=<value>
Statement statement = conn.createStatement();
int result = statement.executeUpdate("sql语句字符串")
int executeUpdate(sql)
insert into
)、删(delete from
)、改(update set
)操作ResultSet executeQuery(sql)
select from
)操作boolean execute(sql)
//使用Statement类的方法executeQuery(String sql);获得结果集类型的对象
ResultSet set = statement.executeQuery(sql);
while(set.next()){
//形参可以直接写字段名,字段名不区分大小写
int id = set.getInt("book_id");
//也可以写字段索引,索引从1开始
int id = set.getInt(1);
}
resultSet.close();
statement.close();
connection.close();
将获取连接和关闭资源等公共、重复的代码封装成一个工具类
import java.sql.*;
public class JDBCUtil {
private static String driver;
private static String url;
private static String user;
private static String passWord;
//解析配置文件.properties
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream("jdbc.properties"));
driver = (String) properties.get("driver");
url = (String) properties.get("url");
user = (String) properties.get("user");
passWord = (String) properties.get("passWord");
}catch (Exception e){
e.printStackTrace();
}
}
//获得Connection对象
public static Connection getConnection(){
Connection connection = null;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url,user,passWord);
}catch (Exception e){
e.printStackTrace();
}
return connection;
}
//关闭资源 -- 针对查询
public static void close(ResultSet resultset,Statement statement,Connection connection){
try {
if (resultset != null) {
resultset.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
//关闭资源 -- 针对增删改
public static void close(Statement statement,Connection connection){
close(null,statement,connection);
}
//针对DML语句--增删改
public static boolean executeUpdate(String sql,List<Object> list){
Connection connection = getConnection();
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(sql);
for (int i = 0;i < list.size();i++){
pre.setObject(i + 1,list.get(i));
}
return (pre.executeUpdate() > 0)? true : false;
}catch (Exception e){
e.printStackTrace();
}finally {
close(pre,connection);
}
return false;
}
//针对查DQL语句
public static <T> List<T> executeQuery(String sql,List<Object> list,Class<T> tClass){
Connection connection = getConnection();
PreparedStatement statement = null;
ResultSet resultSet = null;
List<T> li = new ArrayList<>();
try {
statement = connection.prepareStatement(sql);
for (int i = 0;i < list.size();i++){
statement.setObject(i + 1,list.get(i));
}
resultSet = statement.executeQuery();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
//获取列数
int count = resultSetMetaData.getColumnCount();
//遍历所有行
while (resultSet.next()){
T t = tClass.newInstance();
for (int i = 1;i <= count;i++){
//获取每一列列名
String keyName = resultSetMetaData.getColumnLabel(i);
//获取每一列对应的值
Object value = resultSet.getObject(keyName);
//T中对应的属性
Field key = tClass.getDeclaredField(keyName);
key.setAccessible(true);
key.set(t,value);
}
li.add(t);
}
}catch (Exception e){
e.printStackTrace();
}finally {
close(resultSet,statement,connection);
}
return li;
}
}
List<Map> list = JDBCUtils.executeQuery(sql,new ArrayList());
for (Map<String,Object> map : list){
for (Map.Entry<String,Object> entry : map.entrySet()){
String s = entry.getKey();
Object o = entry.getValue();
System.out.print(s + "=" + o + ",");
}
System.out.println();
}
SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,如下,从而利用系统的 SQL 引擎完成恶意行为的做法。
SELECT user, password FROM user_table WHERE user='lucy' AND password =
# 用户输入密码为:'abc' OR '1' = '1'
SELECT user, password FROM user_table WHERE user='lucy' AND password = 'abc' OR '1' = '1'
对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(继承于Statement) 取代 Statement 就可以了
preparedStatement()
方法获取 PreparedStatement 对象?
作为占位符
SELECT user, password FROM user_table WHERE user='lucy' AND password = ?
setObject(int parameterIndex, Object x)
,可对指定索引的占位符?
进行替换,例如setObject(0,"'abc' OR '1' = '1'")
SELECT user, password FROM user_table WHERE user='lucy' AND password = ''abc' OR '1' = '1''
PreparedStatement,代码的可读性和可维护性更高
PreparedStatement在使用时只需要编译一次,就可以运行多次,Statement每运行一次就编译一次,所以PreparedStatement的效率更高
PreparedStatement 可以防止 SQL 注入
如果拼接表名、列名、关键字,必须使用Statement,防止sql语句错误
通过调用 PreparedStatement 对象的excuteQuery()
方法创建该对象
代表结果集
ResultSet 返回的实际上就是一张数据表,有一个指针指向数据表的第一条记录的前面。
getMetaData()
方法获取该对象getColumnName(int column)
:获取指定索引列的名称getColumnLabel(int column)
:获取指定索引列的别名getColumnCount()
:返回当前ResultSet列数getColumnTypeName(int column)
:获取指定索引列的数据库类型名称getColumnDisplaySize(int column)
:返回指定所有列最大标准宽度,单位字符isNullable(int column)
:返回指定列中的值是否可以为nullisAutoIncrement(int column)
:返回指定索引列是否自增**DAO (Data Access objects 数据访问对象)**是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。能够是代码的结构更加清晰化。