文章目录
本章是关于JDBC 的相关内容,模拟JDBC操作数据库。源码和jar包获取:https://gitee.com/it-sherlock/jdbc-source-code
1. 数据库驱动
一般分是三个部分,先是,调用JDBC这一部分;然后调用JDBC驱动;最后,访问数据库。
2. JDBC
SUN公司为了简化,开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库)
这些规范的实现由具体的厂商去做。
对于开发人员来说,我们只需要掌握JDBC的操作就可以了。
JDBC驱动下载:https://mvnrepository.com/artifact/mysql/mysql-connector-java
3. 第一个 JDBC 程序
创建测试的数据库:
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
USE jdbcStudy
CREATE TABLE users(
id INT PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO users (id,`name`,`password`,email,birthday)
VALUES (1,'zhangsan','123456','zs@qq.com','1999-11-01'),(2,'lisi','123456','ls@qq.com','1229-11-01'),(3,'wangwu','123456','ww@qq.com','2009-11-01');
1. 创建一个项目。
2. 导入数据库驱动jar包。
3. 编写测试代码。
package com.zhangsan.demo01;
import java.sql.*;
// 我的第一个jdbc程序
public class JdbcFistDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1. 加载驱动
Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动
// 2. 用户信息和url
// 三个参数:useUnicode=true&characterEncoding=utf8&useSSL=true
// useUnicode=true :支持中文编码
// characterEncoding=utf8 :设置字符集为utf8
// useSSL=true :使用安全的连接
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username = "root";
String password = "123456";
// 3. 连接成功,数据库对象 这里的connection代表数据库
Connection connection = DriverManager.getConnection(url,username,password);
// 4. 执行sql的对象 Statement用来执行sql的
Statement statement = connection.createStatement();
// 5. 执行sql
String sql = "SELECT * FROM users";
// resultSet :返回的结果集,结果集中封装了我们全部的查询结果
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println("id = " + resultSet.getObject("id"));
System.out.println("name = " + resultSet.getObject("name"));
System.out.println("pwd = " + resultSet.getObject("password"));
System.out.println("email = " + resultSet.getObject("email"));
System.out.println("birthday = " + resultSet.getObject("birthday"));
System.out.println("===============================================");
}
// 6. 释放连接(关闭连接)
// 关闭连接的顺序刚好是反着的
resultSet.close();
statement.close();
connection.close();
}
}
步骤总结:
- 1.加载驱动,Class.forName(“com.mysql.jdbc.Driver”);
- 2.连接数据库 DriverManager
- 3.获得执行sql的对象 Statement
- 4.获得返回的结果集 ResultSet
- 5.释放连接(关闭连接)
DriverManager:
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动
//其实上面的forName就是调用的DiverManager中的registerDriver,使用上推荐使用forName。
//它们两个功能都是一样的,加载驱动
// connection 代表的就是数据库。
Connection connection = DriverManager.getConnection(url,username,password);
// 前面在mysql中所说的事务回滚,事务提交,数据库设置为自动提交,都可以通过connection来操作。
connection.rollback();
connection.commit();
connection.setAutoCommit();
URL:
// 三个参数:useUnicode=true&characterEncoding=utf8&useSSL=true
// useUnicode=true :支持中文编码
// characterEncoding=utf8 :设置字符集为utf8
// useSSL=true :使用安全的连接
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
//mysql 默认端口号:3306
//mysql的URL格式:
//jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3
//oracle 默认端口号:1521
//oracle的URL格式:
//jdbc:oracle:thin:@localhost:1521:sid
//像jdbc:mysql 或者 jdbc.oracle 这些都是一种协议。
Statement执行SQL对象:(还有一个PrepareStatement 也是执行sql对象的)
String sql = "SELECT * FROM users"; // 编写sql
statement.executeQuery("sql语句"); //查询操作,返回resultSet。
statement.execute("sql语句"); //可以执行任何sql,它能执行任何sql就说明它会有一个判断形式,性能比其他语句低。
statement.executeUpdate("sql语句"); // 更新,插入,删除,都是用update操作。
statement.executeBatch("sql语句"); //可以存放多个sql语句,执行。
ResultSet 查询的结果集:封装了所有的查询结果
ResultSet resultSet = statement.executeQuery(sql);
resultSet.getObject("列名"); //在不知道列类型的情况下使用,getObject()
//如果知道列的类型就是用指定类型
resultSet.getString("列名");
resultSet.getInt("列名");
resultSet.getFloat("列名");
resultSet.getDate("列名");
...
ResultSet结果集的遍历,指针操作:
resultSet.beforeFirst(); // 移动到最前面
resultSet.afterLast(); // 移动到最后面
resultSet.next(); // 移动到下一个数据
resultSet.previous(); //移动到前一行
resultSet.absolute(row); //移动到指定行
释放资源:
resultSet.close();
statement.close();
connection.close();
// 一定要释放资源,用完关掉!不然占内存。
4. statement 对象
JDBC中的statement对象用于向数据库发送SQL语句,向完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
- statement对象中的executeUpdate方法,用于向数据库发送增删改查的sql语句,它返回的是一个整数(即增删改语句导致了数据库几行数据发生了变化)。
- statement.executeQuery方法用于像数据库发送查询语句,它返回一个ResultSet对象数据集。
封装数据:
db.properties 文件:用来存储连接数据库的内容。
// db.properties文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456
JdbcUtiles文件:获取db.properties文件内容,驱动加载,获取连接和释放连接操作。
// JdbcUtils文件:
package com.zhangsan.demo02.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try {
//获取db.properties的文件,因为在src下,因此不用链接地址。 这里会返回一个输入流
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in); // 读取字节流种的属性列表
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//1. 驱动加载
Class.forName(driver);
}catch (Exception e){
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//释放连接资源
public static void release(Connection con, Statement st, ResultSet rs){
if (rs!=null){
try{
rs.close();
} catch (SQLException e){
e.printStackTrace();
}
}
if (st!=null){
try{
st.close();
} catch (SQLException e){
e.printStackTrace();
}
}
if (con!=null){
try{
con.close();
} catch (SQLException e){
e.printStackTrace();
}
}
}
}
操作sql语句的文件:增删改查。
//步骤都是一样,就是通过修改sql语句实现。注意是select查询语句有resultset返回集。
package com.zhangsan.demo02;
import com.zhangsan.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
st = conn.createStatement(); //获得sql的执行对象
String sql = "UPDATE users SET `name`='张三',`email`='无' WHERE id=3";
int i = st.executeUpdate(sql);
if (i>0){
System.out.println("更新成功|!!");
}
} catch(SQLException e){
e.printStackTrace();
} finally {
JdbcUtils.release(conn,st,rs);
}
}
}
SQL注入的问题:
sql存在漏洞,会被攻击导致数据泄露,换句话说就是将SQL语句进行拼接。
package com.zhangsan.demo02;
import com.zhangsan.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQL注入 {
public static void main(String[] args) {
//这样我们可以通过login链接数据库完成登录
//login("张三","123456");
//sql注入别的语句操作,这里通过拼接其他的sql语句即便没有密码用户,照样能获取数据库信息。
login("' or '1=1","' or '1=1");
}
// 登录业务
public static void login(String username,String password){
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); // 获取数据库连接
st = conn.createStatement(); //获得sql的执行对象
String sql = "SELECT * FROM users WHERE `name` = '"+username+"' AND `password` = '"+password+"'";
rs = st.executeQuery(sql);
while (rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("password"));
System.out.println("===================================");
}
} catch(SQLException e){
e.printStackTrace();
} finally {
JdbcUtils.release(conn,st,rs);
}
}
}
5. PreparedStatement 对象
PreparedStatement 可以防止SQL注入,并且效率更高。
PreparedStatement是继承了Statement这个类。
依照上面sql注入,采用preparedstatement就可以有效的避免:
package com.zhangsan.demo02;
import com.zhangsan.demo02.utils.JdbcUtils;
import java.sql.*;
public class SQL注入 {
public static void main(String[] args) {
//这样我们可以通过使用PreparedStatement就避免了SQL注入的问题。
//login("老铁","123456");
login("' or '1=1","' or '1=1");
}
// 登录业务
public static void login(String username,String password){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "SELECT * FROM users WHERE `name` = ? AND `password` = ?";
// PreparedStatement 防止SQL注入的本质,把传递进来的参数当作字符。
// 假设其中存在转移字符,比如说: ' 会被直接转义。
st = conn.prepareStatement(sql);
st.setString(1,username);
st.setString(2,password);
rs = st.executeQuery();
while (rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("password"));
System.out.println("===================================");
}
} catch(SQLException e){
e.printStackTrace();
} finally {
JdbcUtils.release(conn,st,rs);
}
}
}
通过PreparedStatement进行的查询操作(增删改也是一样的。):
package com.zhangsan.demo03;
import com.zhangsan.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from users where id=?";
st = conn.prepareStatement(sql);
st.setInt(1,1);
rs = st.executeQuery();
if(rs.next()){
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
6. 使用IDEA连接数据库
打开IDEA,右侧的Database找到MySQL:
(远程阿里云数据库需要用到它的外网地址查询)
Schemas中选择和查看数据库:
修改数据,一定要提交:
在intellij idea 中使用sql语句远程操作数据库:
7. 事务
要么都成功,要么都失败。
1. 开启事务 :conn.setAutoCommit(false);
2. 一组业务执行完毕后,要提交事务: conn.commit()。
3. 可以在catch语句中显示定义回滚语句,并且不定义也是默认回滚的!
创建一个模拟事务的java代码:
package com.zhangsan.demo04;
import com.zhangsan.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false); // 关闭自动提交事务
//实现一次转账
String sql1 = "update account set money = money-100 where name='A'";
st = conn.prepareStatement(sql1);
st.executeUpdate();
int x = 1/0; //模拟失败后,是否回滚
String sql2 = "update account set money = money+100 where name='B'";
st = conn.prepareStatement(sql2);
st.executeUpdate();
//如果两个都成功就要提交事务
conn.commit(); //提交事务
System.out.println("提交事务,成功!");
} catch (Exception e) {
//如果不写也会回滚,默认就是回滚。
try{
System.out.println("回滚事务");
conn.rollback(); // 如果失败则回滚事务
}catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
8. 数据库连接池
对于上面JDBC的过程:
数据库连接 – 执行完毕 – 释放
但是,这个过程一步步是非常浪费时间的,因此才有了池化技术。
已下几个名词要熟记:
池化技术:准备一些预先的资源,过来就连接预先准备好的。
常用连接数:就是平时多少人连接的数量。
最小连接数:这里的最小连接数,最好和常用连接数相同或大点。
最大连接数:最大连接数就是业务最高的承载上限!
排队等待:如果超过了最大连接数,就要排队等待,等待有人释放了连接。
等待超时:超过一定的时间就会结束这次连接,告诉等待者已经超时或报错。
编写连接池,实现一个接口 DataSource。
开源数据源实现:
DBCP
C3P0
Druid(阿里巴巴)
使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了(connection,preparedstatement一系列操作)。
DBCP:
需要的jar包:
commons - dbcp - 版本.jar
commons - pool - 版本 .jar
dbcpconfig.properties文件:
# 连接设置 这里面的名字都是DBCP数据源中定义好的,不能乱其名字!!
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456
#!-- 初始化连接 --
initialSize=10
#最大连接数量
maxActive=50
#!-- 最大空闲连接 --
maxIdle=20
#!-- 最小空闲连接 --
minIdle=5
#!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:user 与 password 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=UTF8
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
JdbcUtils_DBCP文件:
package com.zhangsan.demo05.utils;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils_DBCP {
private static DataSource dataSource = null;
static {
try {
//获取db.properties的文件,因为在src下,因此不用链接地址。 这里会返回一个输入流
InputStream in = com.zhangsan.demo02.utils.JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in); // 读取字节流种的属性列表
//创建数据源 工厂模式-->创建对象
dataSource = BasicDataSourceFactory.createDataSource(properties);
}catch (Exception e){
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); //从数据源中获取连接
}
//释放连接资源
public static void release(Connection con, Statement st, ResultSet rs){
if (rs!=null){
try{
rs.close();
} catch (SQLException e){
e.printStackTrace();
}
}
if (st!=null){
try{
st.close();
} catch (SQLException e){
e.printStackTrace();
}
}
if (con!=null){
try{
con.close();
} catch (SQLException e){
e.printStackTrace();
}
}
}
}
TestDBCP文件:
package com.zhangsan.demo05;
import com.zhangsan.demo05.utils.JdbcUtils_DBCP;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
public class TestDBCP {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try{
conn = JdbcUtils_DBCP.getConnection();
//Statement和PreparedStatement区别:
//PreparedStatement可以使用?占位符来代替参数。
String sql = "INSERT INTO users (id,`name`,`password`,email,birthday) VALUES(?,?,?,?,?)";
// 预编译SQL,先写sql语句,然后不执行。
st = conn.prepareStatement(sql);
// 手动给参数赋值
st.setInt(1,5); //给?索引为1的问号,赋值为4。
st.setString(2,"huasheng");
st.setString(3,"23445");
st.setString(4,"12345666@qq.com");
// 注意这里的sql.Date是数据库的;util.Date是java的。
//这里是将util.Date中获得的时间戳转换为了sql的时间形式。
st.setDate(5,new java.sql.Date(new Date().getTime()));
//执行
int i = st.executeUpdate();
if(i>0){
System.out.println("插入成功!!!");
}
}catch (SQLException e){
e.printStackTrace();
} finally {
JdbcUtils_DBCP.release(conn,st,null);
}
}
}
C3P0:
需要的jar包:
c3p0 - 版本.jar
mchange - commons - java - 版本.jar
C3P0是带日志记录的。
c3p0-config.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- C3P0的默认配置:如果在代码中"ComboPooledDataSource ds = new ComboPooledDataSource();" 这样写就表示进行C3P0的默认配置。-->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/first</property>
<property name="user">root</property>
<property name="password">199657</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property> <!-- intergalactoApp adopts a different approach to configuring statement
caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him -->
</default-config>
<!-- C3P0的命名配置:如果在代码中"ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");"这样写就标识使用的是name为MySQL的配置。-->
<named-config name="MySQL">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true;useSSL=true;characterEncoding=utf8</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property> <!-- intergalactoApp adopts a different approach to configuring statement
caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him -->
</named-config>
</c3p0-config>
JdbcUtils_C3P0文件:
package com.zhangsan.demo05.utils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcUtils_C3P0 {
private static ComboPooledDataSource dataSource = null;
static {
try {
//Java代码版配置:可以直接配置内容,但是很麻烦,因此还是推荐配置文件的类型操作。
//dataSource = new ComboPooledDataSource();
//dataSource.setDriverClass();
//dataSource.setUser();
//dataSource.setPassword();
//dataSource.setJdbcUrl();
//dataSource.setMaxPoolSize();
//dataSource.setMinPoolSize();
//配置文件写法
dataSource = new ComboPooledDataSource("MySQL");
}catch (Exception e){
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); //从数据源中获取连接
}
//释放连接资源
public static void release(Connection con, Statement st, ResultSet rs){
if (rs!=null){
try{
rs.close();
} catch (SQLException e){
e.printStackTrace();
}
}
if (st!=null){
try{
st.close();
} catch (SQLException e){
e.printStackTrace();
}
}
if (con!=null){
try{
con.close();
} catch (SQLException e){
e.printStackTrace();
}
}
}
}
TestC3P0文件:
package com.zhangsan.demo05;
import com.zhangsan.demo05.utils.JdbcUtils_C3P0;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
public class TestC3P0 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try{
conn = JdbcUtils_C3P0.getConnection(); //原来是自己实现,现在用别人的实现
//Statement和PreparedStatement区别:
//PreparedStatement可以使用?占位符来代替参数。
String sql = "INSERT INTO users (id,`name`,`password`,email,birthday) VALUES(?,?,?,?,?)";
// 预编译SQL,先写sql语句,然后不执行。
st = conn.prepareStatement(sql);
// 手动给参数赋值
st.setInt(1,6); //给?索引为1的问号,赋值为4。
st.setString(2,"huasheng");
st.setString(3,"23445");
st.setString(4,"12345666@qq.com");
// 注意这里的sql.Date是数据库的;util.Date是java的。
//这里是将util.Date中获得的时间戳转换为了sql的时间形式。
st.setDate(5,new java.sql.Date(new Date().getTime()));
//执行
int i = st.executeUpdate();
if(i>0){
System.out.println("插入成功!!!");
}
}catch (SQLException e){
e.printStackTrace();
} finally {
JdbcUtils_C3P0.release(conn,st,null);
}
}
}
其实无论怎么使用数据源,它的接口DataSource接口不会变,方法就不会变。
9. 对于JDBC的一些细节补充
9.1 驱动jar版本 和 mysql版本
首先版本,mysql的版本对应的驱动jar包版本,jar包的版本是可以比mysql的版本高的,因为每个jar包版本的设计都会考虑到兼容以前版本。
驱动jar包加载驱动时:
Class.forName(“com.mysql.jdbc.Driver”); 有些版本对应的字节路径,是com.mysql.cj.jdbc.Driver需要注意一下。
9.2 serverTimezone 在mysql8版本是必须设置的一个参数
serverTimezone,在mysql8版本是必须设置的一个参数,我位处于东八区,因此要设定时区!serverTimezone=Asia/Shanghai,这里上海香港都行。这里默认是UTC时区。
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/emp?serverTimezone=Asia/Shanghai", "root", "0818");
9.3 通过索引来获取字段中的内容
9.4 executeUpdate()方法返回值是一个整数
executeUpdate()方法返回值是一个整数,因为它代表影响的行数,此外如果他等于0就代表sql语句执行失败或者数据库没有该要操作的数据,因此我们必须要设定好回滚等等操作,避免错误!!!
10. while循环中next()方法原理
next()方法原理呢,其实就是一个指针,开始指向第一个元素前面的空行(可以这么理解),之后会下调一次判断当前是否有元素,有则返回true,没有则返回false。
11. Properties文件
我们定义数据配置文件使用的是Properties文件。
这个文件的内容就是key=value形式,注意中间不能有空格和冒号分号之类的。
常用的方法还有如下方式:
- 第一种方式:通过类加载器方式调用getResourceAsStream(“db.properties”);
package com.demo.test;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import org.junit.Test;
public class InputStreamTest {
@Test
public void TestInputStream() throws IOException, ClassNotFoundException, SQLException {
//getClassLoader().getResourceAsStream("db.properties"),加载器方式
InputStream inputStream = InputStreamTest.class.getClassLoader().getResourceAsStream("db.propertis");
Properties properties = new Properties();
properties.load(inputStream);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
}
}
- 第二种方式:还可以通过ResourceBundle.getBundle(“db”)方式,这个方法专门用来接收properties文件,因此不用添加后缀!
package com.demo.test;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;
import org.junit.Test;
public class InputStreamTest {
@Test
public void TestInputStream() throws IOException, ClassNotFoundException, SQLException {
String driver = null;
String url = null;
String username = null;
String password = null;
//第二种方式:通过ResourceBundle.getBundle("db")方式,这个方法专门用来接收properties文件,因此不用添加后缀!
ResourceBundle bundle = ResourceBundle.getBundle("db");
driver = bundle.getString("driver");
url = bundle.getString("url");
username = bundle.getString("username");
password = bundle.getString("password");
}
}
- 第三种方式:通过当前线程调用getContextClassLoader()方法在调用getResourceAsStream()方法来返回输入流。
package com.demo.test;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;
import org.junit.Test;
public class InputStreamTest {
@Test
public void TestInputStream() throws IOException, ClassNotFoundException, SQLException {
String driver = null;
String url = null;
String username = null;
String password = null;
//第三种方式:通过当前线程调用getContextClassLoader()方法在调用getResourceAsStream()方法来返回输入流。
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
}
}
这里解释一下: getClassLoader()是当前类加载器,而getContextClassLoader是当前线程的类加载器。
12. 如何解决java代码向mysql数据库存入年月日时分秒级别的日期
java.sql.date只能精确到年月日,怎么对应数据库精确到时分秒的datetime类型。已解决,使用timestamp对象来操作。
- Timestamp timestamp = new Timestamp(System.currentTimeMillis());
preparestatement.setTimestamp(1, timestamp);
13. 不常用但是很重要的sql语句
mysql删除外键的指令。
alter table 表名 drop foreign key 字段名;