一、认识JDBC
JDBC
是用于在Java
语言编程中与数据库连接的API
.JDBC
是一个规范,它提供了一整套接口,允许以一种可移植的访问底层数据库API
。使用JDBC驱动程序
来访问数据库,并用于存储数据到数据库中.
解释上面两幅图:
java应用程序通过JDBC API首先连接到JDBC Driver,这些JDBC驱动器都是由各大数据库厂家针对JDBC提供的,我们可以在网上下载jar包来使用,然后通过JDBC驱动器就能连接到我们的数据库了。
第一步 添加驱动
1.在项目当中创建一个文件夹为lib
2.把Mysql驱动包复制到该文件夹下
3.builder path 编译路径
复制代码
第二步 连接到数据库
package con.meils.jdbc.conn;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionClass {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// TODO Auto-generated method stub
// 1、加载驱动
// 把com.mysql.jdbc.Driver这份字节码加载进JVM
// 当一份字节码加载进JVM的时候,就会执行字节码文件中的静态代码块
// 这里加载该字节码之后会实例化一个驱动器
Class.forName("com.mysql.jdbc.Driver");
// 2、连接
String url = "jdbc:mysql://localhost:3306/mytest";
String username = "root";
String password = "zjj19970517";
Connection connection = DriverManager.getConnection(url, username, password);
// 3、验证连接
System.out.println(connection); // 如果有输出,表明连接成功
}
}
复制代码
第三步 操作数据库创建表
package con.meils.jdbc.ddl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class CreateTable {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 1\加载驱动
// 把com.mysql.jdbc.Driver这份字节码加载进JVM
// 当一份字节码加载进JVM的时候,就会执行字节码文件中的静态代码块
// 这里加载该字节码之后会实例化一个驱动器
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/jdbc_db";
String username = "root";
String password = "zjj19970517";
// 2\ 连接数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 3\创建sql语句
String sql = "create table stu (id int , name varchar(20), age int)";
// 4\执行sql语句
Statement st = connection.createStatement();
int row = st.executeUpdate(sql);
// 5\释放
st.close();
connection.close();
}
}
复制代码
为什么要释放资源呢?
第四步 插入数据
package con.meils.jdbc.dml;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class InsertClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
// ================ 插入数据 ================
Connection conn = null;
Statement st = null;
try {
// 1、加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2、创建连接
String url = "jdbc:mysql://localhost:3306/mytest";
String user = "root";
String password = "zjj19970517";
conn = DriverManager.getConnection(url, user, password);
// 3、创建sql语句
String sql = "insert into stu values(1, 'zjj', 20)";
st = conn.createStatement();
// 4、执行语句
int row = st.executeUpdate(sql);
System.out.println(row);
}catch (Exception e) {
e.printStackTrace();
} finally {
// 5、释放
if(st!=null) {
try {
st.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
复制代码
第五步 查询操作
package con.meils.jdbc.dql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class QueryClass {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
// TODO Auto-generated method stub
// ================ 查询数据 ================
// 1\加载驱动
// 把com.mysql.jdbc.Driver这份字节码加载进JVM
// 当一份字节码加载进JVM的时候,就会执行字节码文件中的静态代码块
// 这里加载该字节码之后会实例化一个驱动器
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mytest";
String username = "root";
String password = "zjj19970517";
// 2\ 连接数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 3\创建sql语句
String sql = "select count(*) as total from stu"; // 查询一共有几行数据
// 4\执行sql语句
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery(sql);
if(rs.next()) {
int count = rs.getInt("total");
System.out.println(count); // 1
}
// 5\释放
st.close();
connection.close();
}
}
复制代码
数据类型对照表:
上面我们基本学会了如何与数据库打交道,但是这样使用存在许多的弊端,比如:每一步操作都进行一次数据库连接,造成浪费,所以我们在实际中要使用DAO思想来处理。
二、DAO设计
1、什么是DAO
DAO(Data Access Object)数据存储对象,介于业务逻辑层和持久层之间,实现持久化数据访问。
不使用DAO的时候:
使用DAO的情况:
三、ORM映射关系
四、Domain
1、认识domain
2、domain类
3、保存数据
4、获取数据
五、DAO设计规范
案例
我们可以编写一个DAO接口,定义了常用的数据库操作方法,这时候我们同时会连接多个数据库,比如是mysql 和 oracle ,我们可以分别实现oracleDao和mysqlDao两个类,不同类里面定义不同的操作数据库的代码,实现的功能确实相同的。
所以面向接口编程是很重要的,也是一个很好的方式。
1、包命名规范
2、类命名规范
3、开发步骤
目录如下
内容实现:
接口实现类的具体内容:
package com.meils.jdbc.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.meils.jdbc.dao.IStudentDao;
import com.meils.jdbc.domain.Student;
import com.meils.jdbc.utils.JdbcUtil;
/**
* 实现DAO接口的类
* @author apple
*
*/
public class StudentDaoImpl implements IStudentDao{
@Override
/**
* 存储学生
* @param stu
*/
public void save(Student stu) {
// TODO Auto-generated method stub
Connection conn = null;
PreparedStatement ps = null;
try {
// 连接数据库
conn = JdbcUtil.getConnection();
String sql = "insert into student (name, age) values (? , ?)";
// 创建预编译
ps = conn.prepareStatement(sql);
ps.setString(1, stu.getName());
ps.setInt(2, stu.getAge());
// 执行更新
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps, null);
}
}
@Override
public void delete(int id) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 连接数据库
conn = JdbcUtil.getConnection();
String sql = "delete from student where id = ?";
// 创建预编译
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
// 执行更新
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps, null);
}
}
@Override
public void update(int id, Student stu) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
String sql = "update student set name=?, age=? where id = ? ";
ps = conn.prepareStatement(sql);
ps.setString(1, stu.getName());
ps.setInt(2, stu.getAge());
ps.setInt(3, id);
// 执行
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps, null);
}
}
@Override
public Student findOne(int id) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
// sql语句
String sql = "select * from student where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
// 执行
rs = ps.executeQuery();
if (rs.next()) {
// 保存数据
Student stu = new Student();
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
stu.setId(rs.getInt("id"));
return stu;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 销毁
JdbcUtil.close(conn, ps, rs);
}
return null;
}
@Override
public List<Student> findAll() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
st = conn.createStatement();
String sql = "select * from student ";
rs = st.executeQuery(sql);
List<Student> list = new ArrayList<Student>();
while (rs.next()) {
Student stu = new Student();
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
stu.setId(rs.getInt("id"));
list.add(stu);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, st, rs);
}
return null;
}
}
复制代码
编写测试类:
package com.meils.jdbc.dao.test;
import java.util.List;
import org.junit.Test;
import com.meils.jdbc.dao.IStudentDao;
import com.meils.jdbc.dao.impl.StudentDaoImpl;
import com.meils.jdbc.domain.Student;
/**
* StudentDao测试类
* @author apple
*/
public class StudentDaoTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
@Test
public void save() {
Student stu = new Student();
stu.setName("张伟");
stu.setAge(21);
IStudentDao dao = new StudentDaoImpl();
dao.save(stu);
}
@Test
public void delete() {
IStudentDao dao = new StudentDaoImpl();
dao.delete(4);
}
@Test
public void update () {
Student stu = new Student();
stu.setName("mmmmm");
stu.setAge(16);
IStudentDao dao = new StudentDaoImpl();
dao.update(5, stu);
}
@Test
public void findOne() {
IStudentDao dao = new StudentDaoImpl();
Student stu = dao.findOne(5);
System.out.println(stu);
}
@Test
public void findAll() {
IStudentDao dao = new StudentDaoImpl();
List<Student> allStu = dao.findAll();
System.out.println(allStu);
}
}
复制代码
JDBC工具类:
package com.meils.jdbc.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* JDBC 工具类
* @author apple
*
*/
public class JdbcUtil {
// 配置信息
public static String driverName = "com.mysql.jdbc.Driver";
public static String url = "jdbc:mysql://localhost:3306/mytest";
public static String userName = "root";
public static String password = "zjj19970517";
static {
try {
// 加载驱动,因为是在static块中,所以只会加载一次
Class.forName(JdbcUtil.driverName);
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 连接数据库
* @return 返回连接对象
*/
public static Connection getConnection() {
try {
return DriverManager.getConnection(JdbcUtil.url, JdbcUtil.userName, JdbcUtil.password);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 关闭连接,并释放资源
* @param conn
* @param st
* @param rs
*/
public static void close(Connection conn, Statement st, ResultSet rs) {
if(conn!=null) {
try {
conn.close();
}catch(Exception e) {
e.printStackTrace();
}
}
if(st!=null) {
try {
st.close();
}catch(Exception e) {
e.printStackTrace();
}
}
if(rs!=null) {
try {
rs.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
复制代码
3、DAO代码重构
4、Statement接口
1 Statement 是父接口,PreparedStatement 和 CallableStatement 是子接口。
2 Statement 用于java应用程序与数据库之间的传送数据,比如传送sql语句过去,到数据库执行操作。
3 Statement 用于通用的访问,使用静态sql,其实并不好,容易SQL注入
4 PreparedStatement 用于预编译模版SQL语句,可以在运行的时候传入参数
5 CallableStatement 访问存储过程的时候使用
复制代码
5、预编译语句
防止SQL注入:
6、通过DB类来操作数据库
JDBC的另一种封装方法:
package com.meils.jdbc.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class MysqlDB {
Connection conn = null; // 创建连接对象
Statement st = null; // 创建编译语句对象
PreparedStatement ps = null; // 创建预编译语句对象
ResultSet rs1 = null; // 结果集
// 配置信息
// 驱动名称
private static final String driverName = "com.mysql.jdbc.Driver";
// 数据库的地址
private static final String URL = "jdbc:mysql://localhost:3306/mytest";
// 数据库登录用户名
private static final String userName = "root";
// 数据库登录密码
private static final String pwd = "zjj19970517";
/**
* 连接数据库
* @return
*/
public Connection getConnection() {
try {
Class.forName(driverName);
this.conn = DriverManager.getConnection(URL, userName, pwd);
System.out.println("连接成功");
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 构造函数
public MysqlDB() {
this.getConnection();
}
/**
* 查询
* @param sql sql语句,完整的语句,查询一般比较安全
* @return
*/
public ResultSet query(String sql) {
try {
this.st = this.conn.createStatement();
this.rs1 = this.st.executeQuery(sql);
return rs1;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 更新
* @param sql // 预编译sql语句
* @param args // 参数数组
*/
public void update(String sql, String [] args) {
try {
this.ps = this.conn.prepareStatement(sql);
for (int i = 0 ; i < args.length ; i++) {
this.ps.setString(i+1, args[i]);
}
this.ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
this.close();
}
}
/**
* 删除
* @param sql
* @return
*/
public int delete(String sql){
try {
this.st = this.conn.createStatement();
int num = this.st.executeUpdate(sql);
return num;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
this.close();
}
return 0;
}
/**
* 释放资源
*/
public void close () {
try {
if(rs1!=null) {
rs1.close();
}
if(st!=null) {
st.close();
}
if(ps!=null) {
ps.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
复制代码
测试以下:
package com.meils.jdbc.db;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
// Conn();
delete();
}
// 测试连接
public static void Conn() {
MysqlDB m = new MysqlDB();
}
// 测试查询
public static void queryTest() {
MysqlDB m = new MysqlDB();
String sql = "select * from student";
ResultSet result = m.query(sql);
System.out.println(result);
try {
while (result.next()) {
System.out.println(result.getString("name"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
m.close();
}
}
// 更新
public static void update() {
MysqlDB m = new MysqlDB();
String sql = "update student set name = ? where id = ?";
String [] args = {"梅子111", "7"};
m.update(sql, args);
}
// 删除
public static void delete() {
MysqlDB m = new MysqlDB();
String sql = "delete from student where id = 8";
System.out.println(m.delete(sql));
}
}
复制代码
7、调用存储过程
首先我们熟悉一下存储过程
// 新建存储过程
DELIMITER //
create PROCEDURE getStudent1(in n varchar(20))
BEGIN
select * from student where name = n;
END //
DELIMITER ;
// 执行
call getStudent1('张锦杰');
复制代码
测试一下: (非常尴尬好像并没有结果,也没有报错,不知道是什么原因~~)
package com.meils.jdbc.dao.test;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import com.meils.jdbc.domain.Student;
import com.meils.jdbc.utils.JdbcUtil;
public class ProductTest {
public static void main(String[] args) {
CallableStatement cstmt = null;
try {
//1.连接
Connection conn = JdbcUtil.getConnection();
//2.
CallableStatement cs = conn.prepareCall("{ call getStu(?)}");
//3.设置参数
cs.setString(1, "张锦杰");
//4.执行
ResultSet rs = cs.executeQuery();
if(rs.next()) {
Student stu = new Student();
stu.setId(rs.getInt("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
System.out.println(stu);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码
带有参数和输出的存储过程
// 带有参数和输出的存储过程
DELIMITER //
CREATE PROCEDURE getName ( IN i INT, OUT n VARCHAR ( 50 ) ) BEGIN
SELECT NAME INTO
n
FROM
student
WHERE
id = i;
END // DELIMITER;
call getName(1, @name);
select @name;
复制代码
测试一下:
package com.meils.jdbc.dao.test;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import com.meils.jdbc.domain.Student;
import com.meils.jdbc.utils.JdbcUtil;
public class ProductTest {
public static void main(String[] args) {
CallableStatement cstmt = null;
try {
//1.创建连接
Connection conn = JdbcUtil.getConnection();
//2.创建预编译语句
CallableStatement cs = conn.prepareCall("{ call getName(?,?)}");
//3.设置参数
cs.setInt(1, 1);
//4.设置输出参数
cs.registerOutParameter(2, Types.VARCHAR);
//5.执行
cs.execute();
//6.获取到输出的参数
String name = cs.getString(2);
System.out.println(name); // 张锦杰
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码
8、事物
实例:
首先在减少钱之前关闭自动提交事务,期间可以进行多个操作,此时的事务提交必须手动了,需要使用conn.commit();
。如果在中间发生了异常,那么就进行回滚,释放资源。
9、批处理
通常情况下如果我们想要一次性执行许多条sql语句,我们都是一条执行完毕再执行下一条,当我们使用了批处理之后,我们就可以一次性执行多条语句,话费的事件将大大缩短。
10、将文件存入数据库
通常我们不会这么做的,因为数据库的空间是非常宝贵的,文件较大,占用的空间也较大,成本也就高了,假如我们需要存文件,那么就要选择blob类型了,它是以二进制的形式来存取的,可以存视频、图片、等多媒体信息。
首先需要设置数据库中的字段类型为blob。
复制代码
存储文件到数据库:
将数据库中的文件取出来:
11、获取自动生成的主键id
需求分析:
我们可能回遇到这样的情景,我们首先注册信息,填入用户明和密码后,注册成功,此时的数据库中的id是自动添加进去的,接下来回让自己去完善自己的信息,这就要需要我们刚才创建的id了,那么如何返回id给我们下次使用呢?
两种方式获取:
1:
2: