- 一个坑:connector 别用太新 https://www.cnblogs.com/tanhao/p/7456104.html
(这里用mysql-connector-java-5.1.13)
0.0 Navicat 使用
2.1JDBC概述
2.1.1 什么是JDBC?为什么要学习JDBC?
<mark>JDBC( Java DataBase Connectivity )</mark> 翻译过来就是<mark>Java数据库连接</mark>
其实就是通过Java语言操作数据库的一门技术。
之前我们可以通过cmd或者navicat等工具连接并访问数据库,但是以后在<mark>企业</mark>级的开发中,我们<mark>更多的是使用JDBC(或者底层是JDBC的框架)来连接并访问数据库</mark>。
使用Java语言连接数据库,就得通过JDBC这门技术!
hibernate
mybatis
底层都是jdbc
2.1.2 如何通过JDBC程序访问数据库?
1. 提出需求:
创建一个 jt_db 数据库,在库中创建一个Account表,并插入三条记录,<mark>然后利用Java程序查询出Account表中所有的记录,并打印在控制台上</mark>.
2. 开发步骤:
- <mark>准备数据</mark>
创建jt_db库, 创建account表
drop database if exists jt_db;
create database jt_db charset utf8;
use jt_db;
create table account(
id int primary key auto_increment,
name varchar(50),
money double
);
insert into account values(null, 'tom', 1000);
insert into account values(null, 'andy', 1000);
insert into account values(null, 'tony', 1000);
select * from account ;
- 创建JAVA工程
- 导入jar包
<mark>jar包 - 别人写好的类,打包成压缩包,压缩包后缀为“.jar”</mark>
导入jar包:mysql-connector-java-5.1.32.jar
下载链接:
- mysql官网:https://dev.mysql.com/downloads/
- 网上各个版本:https://mvnrepository.com/artifact/mysql/mysql-connector-java
- 我的下载:https://download.csdn.net/download/LawssssCat/12011431
- 创建类并实现JDBC程序(六个步骤)
3. 代码
package com.edut.cn.tarena.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
/** * 实现JDBC快速入门程序 * 表中的所有记录,将记录输出到控制台上 * */
public class JDBCDemo {
@Test
public void testFindAll() throws ClassNotFoundException, SQLException {
//1. 注册数据库驱动(Driver) - 导入jar包:mysql-connector-java
Class.forName("com.mysql.jdbc.Driver") ;
/** * 解释: * ------- * jdbc:jdbc服务 * mysql:使用mysql的jdbc服务 * jdbc:mysql: 协议总名称 * localhost:使用本地的mysql的jdbc服务 * 3306:使用本地的3306端口的mysql的jdbc服务 * ------- * jt_db 使用的数据库 * characterEncoding=utf-8 设置编码utf-8 * * 面向接口编程 - 思想 */
//2. 获取数据库连接
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8",
"root",
"root");
/** * statement : 声明 */
//3. 获取传输器
Statement stat = conn.createStatement();
String sql = "select * from account;";
//4. 执行SQL语句,返回执行结果
ResultSet rs = stat.executeQuery(sql);
/** * 理解ResultSet结构: * +----+------+-------+ * | id | name | money | 表头 ←—————————— 指向1 rs.next() true/false * +----+------+-------+ ←—————————— 指向2 true rs.get类型("列名") * | 1 | tony | 1000 | ... * | 2 | tom | 1000 | ... * | 3 | andy | 1000 | ←—————————— 指向n true rs.get类型("列名") * +----+------+-------+ ←—————————— 指向n false rs.get类型("列名") */
//5. 处理结果
while (rs.next()) {
int id = rs.getInt("id") ;
String name = rs.getString("name");
double money = rs.getDouble("money");
System.out.println(id+" : "+ name+" : "+ money);
}
//6. 释放资源
rs.close();
stat.close();
conn.close();
}
}
4. 执行结果
2.1.3JDBC API总结
1、 注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");
在Driver类中,有一个静态代码块,静态代码块中有一行注册驱动的代码;
DriverManager.registerDriver(new Driver());
所谓的<mark>注册驱动</mark>,就是让JDBC程序加载mysql驱动程序,并管理驱动
驱动程序实现了JDBC API定义的接口以及和数据库服务器交互的功能,加载驱动是为了方便使用这些功能。
2、获取连接之数据库URL
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8",
"root", "root"
);
DriverManager.getConnection() 用于获取数据连接,
返回的Connection连接对象是JDBC程序连接数据库至关重要的一个对象。
- <mark>参数2</mark>和<mark>参数3</mark>分别是所连接<mark>数据库的用户名</mark>和<mark>密码</mark>。
- <mark>参数1</mark>:“jdbc:mysql://localhost:3306/jt_db” 是连接数据库的URL,用于指定访问哪一个<mark>位置</mark>上的数据库<mark>服务器</mark>及服务器中的哪一个<mark>数据库</mark>,其写法为:
当连接本地数据库,并且端口为3306,可以简写为如下形式:
jdbc:mysql:///jt_db
3、Statement传输器对象
Statement stat = conn.createStatement();
该方法返回用于向数据库服务器发送sql语句的Statement传输器对象,该对象上提供了发送sql的方法:
executeQuery(String sql) -- 用于向数据库发送查询类型的sql语句,返回一个ResultSet对象中
executeUpdate(String sql) -- 用于向数据库发送更新(增加、删除、修改)类型的sql语句,返回一个int值,表示影响的记录行数
4、ResultSet结果集对象
ResultSet对象用于封装sql语句查询的结果,也是一个非常重要的对象。
该对象上提供了遍历数据及获取数据的方法。
- 遍历数据行的方法
next() //使指向数据行的索引向下移动一行
- 获取数据的方法
getInt(int columnIndex)
getInt(String columnLable)
getString(int columnIndex)
getString(String columnLable)
getDouble(int columnIndex)
getDouble(String columnLable)
getObject(int columnIndex)
getObject(String columnLable)
...
5、释放资源
rs.close();
stat.close();
conn.close();
此处释放资源<mark>必须按照一定的顺序释放</mark>,越晚获取的越先关闭。
所以先关闭 rs对象,再关闭stat对象,最后关闭conn对象。
另,为了避免上面的程序抛出异常,释放资源的代码不会执行,
<mark>应该把释放资源的代码放在finally块中.</mark>
try{
...
}catch(Exception e){
...
}finally{
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
rs = null;
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
stat = null;
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
2.2 增删改查 - 练习
0、写个工具类
package com.edut.cn.tarena.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcUtil {
/** * 注册驱动并获取连接对象 * @return Connection 连接对象 * @throws SQLException * @throws ClassNotFoundException */
public static Connection getConn() throws SQLException, ClassNotFoundException {
//1. 注册数据库驱动(Driver)
Class.forName("com.mysql.jdbc.Driver");
//2. 获取数据库连接
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8",
"root",
"root");
return conn;
}
/** * 将JDBC程序中的连接、传输器、结果集释放掉 * @param conn 连接对象 * @param stat 传输器对象 * @param rs 结果集对象 */
public static void close(
Connection conn ,
Statement stat,
ResultSet rs ) {
//6. 释放资源
if(rs != null) { //rs用了资源
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//关闭失败,让对象编程游离对象,等待gc回收。
rs = null;
}
}//如果进上面循环,rs没用到资源 =》 不用对rs进行任何操作
if (stat!=null) {
try {
stat.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
stat = null ;
}
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
conn = null;
}
}
}
/** * 打印查询语句 * @param stat 传输器 * @param sql 查询语句 * @return * @throws SQLException */
public static ResultSet Qurey(Statement stat, String sql) throws SQLException {
ResultSet rs = stat.executeQuery(sql) ;
ResultSetMetaData rsmd = null ; //结果原数据
rsmd = rs.getMetaData();
int col = rsmd.getColumnCount();
while(rs.next()) {
StringBuilder sb = new StringBuilder("[ ");
Object obj = null ;
for (int i = 1; i<=col; i++) {
obj=rs.getObject(i) ;
sb.append(obj.toString()) ;
sb.append(" : ") ;
}
sb.delete(sb.length()-2, sb.length());
sb.append("]");
System.out.println(sb);
}
return rs;
}
}
1、增删改查 - 实现
package com.edut.cn.tarena.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
import com.edut.cn.tarena.util.JdbcUtil;
/** * CRUD 增删改查 * ------------- * Create 增 * Retrieve 查 * Update 改 * Delete 删 */
public class Test_JDBC_CRUD {
/** * 1、新增:往account表中添加一个名称为john、money为3500的记录 */
@Test
public void testInsert() {
System.out.println("\n1、新增:往account表中添加一个名称为john、money为3500的记录");
Connection conn = null; //连接
Statement stat = null; //传输器
ResultSet rs = null ; //结果器
try {
conn = JdbcUtil.getConn();
stat = conn.createStatement();
String sql1 = "insert into account value(null,\"john\",3500);";
//添加前,查询
rs = JdbcUtil.Qurey(stat , "select * from account" );
int updateRow = stat.executeUpdate(sql1);
System.out.println("影响行数:"+updateRow);
//添加后,查询
rs = JdbcUtil.Qurey(stat , "select * from account" );
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JdbcUtil.close(conn, stat, rs );
}
}
/** * 2、修改:将account表中名称为john的记录,money修改为1500 */
@Test
public void testUpdate() {
System.out.println("\n2、修改:将account表中名称为john的记录,money修改为1500");
Connection conn = null ;
Statement stat = null;
ResultSet rs = null ;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jt_db?characterEncoding=gbk","root" , "root");
stat = conn.createStatement() ;
rs = JdbcUtil.Qurey(stat, "select * from account ;");
String sql = "update account set money=1500 where name = 'john' ; " ;
boolean updateRow = stat.execute(sql);
System.out.println("影响行数:"+updateRow);
rs = JdbcUtil.Qurey(stat, "select * from account ;");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JdbcUtil.close(conn, stat, rs);
}
}
/** * 3、查询:查询account表中名称为john的记录 */
@Test
public void testRetrieve() {
System.out.println("\n3、查询:查询account表中名称为john的记录");
Connection conn = null;
Statement stat = null;
ResultSet rs = null ;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/jt_db?characterEncoding=gbk"
,"root","root") ;
stat = conn.createStatement();
String sql = "select * from account where name='john';" ;
rs = stat.executeQuery(sql);
ResultSetMetaData metaData = rs.getMetaData();
int col = metaData.getColumnCount();
while(rs.next()) {
StringBuilder sb = new StringBuilder("[ ");
for (int i = 1; i <= col; i++) {
sb.append(rs.getString(i).toString());
sb.append(", ");
}
sb.delete(sb.length()-", ".length(), sb.length());
sb.append(" ]");
System.out.println(sb);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JdbcUtil.close(conn, stat, rs);
}
}
/** * 4、删除:删除account表中名称为john的记录 */
@Test
public void testDelete() {
System.out.println("\n4、删除:删除account表中名称为john的记录");
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(
"jdbc:mysql:///jt_db?characterEncoding=utf-8",
"root",
"root");
stat = conn.createStatement() ;
rs = JdbcUtil.Qurey(stat, "select name from account ;");
String sql = "delete from account where name = 'john';";
int updateRow = stat.executeUpdate(sql);
System.out.println("影响行数:"+updateRow);
rs = JdbcUtil.Qurey(stat, "select name from account ;");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(conn!=null) { //调用了连接资源
try {
conn.close();
} catch (SQLException e) { // 关闭失败
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
conn=null; //对象 设置为游离对象
}
}
if(stat!=null){
try {
stat.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
stat=null;
}
}
if(rs!=null) {
try {
rs.close();
}catch(SQLException e) {
e.printStackTrace();
}finally {
rs = null;
}
}
}
}
}
2、 测试结果
3、查询:查询account表中名称为john的记录
[ 6, john, 1500 ]
4、删除:删除account表中名称为john的记录
[ tony ]
[ tom ]
[ andy ]
[ john ]
影响行数:1
[ tony ]
[ tom ]
[ andy ]
1、新增:往account表中添加一个名称为john、money为3500的记录
[ 1 : tony : 1000.0 ]
[ 2 : tom : 1000.0 ]
[ 3 : andy : 1000.0 ]
影响行数:1
[ 1 : tony : 1000.0 ]
[ 2 : tom : 1000.0 ]
[ 3 : andy : 1000.0 ]
[ 7 : john : 3500.0 ]
2、修改:将account表中名称为john的记录,money修改为1500
[ 1 : tony : 1000.0 ]
[ 2 : tom : 1000.0 ]
[ 3 : andy : 1000.0 ]
[ 7 : john : 3500.0 ]
影响行数:false
[ 1 : tony : 1000.0 ]
[ 2 : tom : 1000.0 ]
[ 3 : andy : 1000.0 ]
[ 7 : john : 1500.0 ]
2.5扩展:切换工作空间,修改默认编码
2.5.1 切换新的工作空间,设置工作空间编码为utf-8
- <mark>切换到新的工作空间</mark>目的:若旧的工作空间<mark>内容过多</mark>,<mark>可能会导致eclipse不编译</mark>,甚至进入休眠状态。
- 设置工作空间编码为utf-8,此后在当前工作空间下创建的项目编码也默认是utf-8。