目录
1.JDBC简介
2. JDBC体系结构
3 JDBC核心组件(工具类)
4.JDBC使用步骤
5.JDBC连接步骤详解
5.1.导入JDBC包
5.2.注册驱动程序2种方法
5.3.数据库连接地址URL配置和创建数据库连接对象
5.4.JDBC执行SQL语句
5.5.关闭数据库连接
6.JDBC演示CRUD
7.SQL注入问题
8.预状态通道解决SQL注入
9.对比statement和PreparedStatement
10.Java操作两表关系
10.1.一对多(老师-学生)
10.2.多对一(学生->老师)
10.3.一对一(妻子丈夫)
10.4.多对多(科目-学生)
11.数据库事务
11.1.事务概述
11.2.事务四大特性
11.3.JDBC中事务应用
11.4.事务的提交和回滚
11.5.Savepoints
11.6.事务案例-转账
12.JDBC批处理
12.1.Statement批处理
12.2.PreparedStatement批处理
13.反射处理(简化)结果集
14.原生JDBC抽取的工具类
15.连接池
15.1.自定义连接池
15.1.1.数据连接池原理
15.1.2.自定义连接池
15.1.3.java规范实现连接池
15.1.4.基于规范实现的连接池
15.1.5.连接池参数
15.2.DBCP连接池
15.3.DBCP与C3P0区别
15.3.C3P0连接池
15.4.Druid(德鲁伊)连接池
15.5.获取连接4种方法
JDBC在整个项目中是如何操作的?执行流程
DriverManager:
方法一:Class.forName();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
}catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
}
方法二:DriverManager.registerDriver()
try {
Driver myDriver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver( myDriver );
}catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
}
1.DriverManager.getConnection()
2.不同的数据库对应的JDBC驱动程序和连接地址url都不同
jdbc:mysql://localhost:3306/数据库名? useSSL=false&useUnicode=true&characterEncoding=UTF-8
3.创建数据库连接对象
CREATE TABLE `subjecttable` (
`subjectid` int NOT NULL,
`subject_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`subject_time` int DEFAULT NULL,
`gradeid` int DEFAULT NULL,
PRIMARY KEY (`subjectid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
package demo01;
import java.sql.*;
/**
* JDBC操作步骤
*/
public class Demo1 {
public static void main(String[] args) throws SQLException {
Connection conn=null;
Statement statement=null;
ResultSet resultSet=null;
try{
//0.导入JDBC API(jdbc jar包),程序可以调用这些API
//1.注册JDBC驱动程序--打开程序与数据库的通信通道
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接--即通过连接地址url,用户名和密码连接上数据库student
String userName="root";
String passWord="你自己密码";
String url="jdbc:mysql://localhost:3306/student?serverTimezone=UTC";
conn = DriverManager.getConnection(url,userName,passWord);
//3.执行sql语句--创建状态通道Statement,执行sql语句的发送
statement = conn.createStatement();
System.out.println("JDBC查询操作:");
//4.executeQuery(sql)执行查询的时候使用,返回结果集
resultSet = statement.executeQuery("select * from subjecttable");
//5.获取结果集信息
while (resultSet.next()){
//取出数据:resultSet.getXXX("列名"); XXX表述列名的类型
System.out.println("科目编号:"+resultSet.getInt("subjectid")
+",科目名称:"+resultSet.getString("subject_name")
+",科目学时:"+resultSet.getInt("subject_time")
+",科目阶段:"+resultSet.getInt("gradeid")
);
}
System.out.println("JDBC插入操作");
//5.executeUpdate(sql)执行增删改的时候使用,返回受影响的行数
int result = statement.executeUpdate("insert into subjecttable values(5,'Java',100,3)");
if (result>0){
System.out.println("插入操作执行成功");
}else {
System.out.println("插入操作执行失败");
}
System.out.println("JDBC修改操作:");
int result1 = statement.executeUpdate("update subjecttable set subject_time=5000");
if (result>0){
System.out.println("执行成功,受影响的行数:"+result);
}else {
System.out.println("执行失败");
}
}catch (ClassNotFoundException e){
e.printStackTrace();
}catch (SQLException throwables){
throwables.printStackTrace();
}finally {
//5.关闭资源,需要判空
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
conn.close();
}
}
}
}
String userid = "aaa";
String pass = " 'abc' or 1=1 ";
resultSet = statement.executeQuery(
"select * from login where userid='" + userid + "' and pass=" + pass
);
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
用户名密码都不对,也能登录上。
如何解决的:
演示:
//0.导入JDBC API(jdbc jar包),程序可以调用这些API
//1.注册JDBC驱动程序--打开程序与数据库的通信通道
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接--即通过连接地址url,用户名和密码连接上数据库student
String userName = "root";
String passWord = "你自己密码";
String url = "jdbc:mysql://localhost:3306/student?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userName, passWord);
//定义sql
String sql="select * from login where userid= ? and pass=? ";
//3.执行sql语句--创建预状态通道PreparedStatement,执行sql语句的发送
pps = conn.prepareStatement(sql);
//给占位符设置
String userid = "aaa";
String pass = " '' or 1=1 ";
pps.setString(1,userid);
pps.setString(2,pass);
resultSet = pps.executeQuery();
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
说明
先启动mysql服务器
(老师角度)
CREATE TABLE `student` (
`stuid` int(11) NOT NULL AUTO_INCREMENT,
`stuname` varchar(255) DEFAULT NULL,
`teacherid` int(11) DEFAULT NULL,
PRIMARY KEY (`stuid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
INSERT INTO `student` VALUES ('1', 'aaa', '3');
INSERT INTO `student` VALUES ('2', 'bb', '1');
INSERT INTO `student` VALUES ('3', 'cc', '3');
INSERT INTO `student` VALUES ('4', 'dd', '1');
INSERT INTO `student` VALUES ('5', 'ee', '1');
INSERT INTO `student` VALUES ('6', 'ff', '2');
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`tid` int(11) NOT NULL AUTO_INCREMENT,
`tname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `teacher` VALUES ('1', '张三老师');
INSERT INTO `teacher` VALUES ('2', '李四老师');
INSERT INTO `teacher` VALUES ('3', '王五');
package bean;
/**
* student表对应的java实体类
* 老师-学生 一对多
*/
public class Student {
private int stuid;
private String sname;
//外键列一般不生成属性
private int teacherid;//在多方设置外键指向一方的主键
public int getStuid() { return stuid; }
public void setStuid(int stuid) { this.stuid = stuid; }
public String getSname() { return sname; }
public void setSname(String sname) { this.sname = sname; }
public int getTeacherid() { return teacherid; }
public void setTeacherid(int teacherid) { this.teacherid = teacherid; }
}
package bean;
import java.util.ArrayList;
/**
* teacher表对应的实体类
* teacher-student 一对多关系
*/
public class Teacher {
private int tid;
private String tname;
//在一方定义集合属性,存储多方的信息,达到两表关联效果
ArrayListlist =new ArrayList<>();
public int getTid() { return tid; }
public void setTid(int tid) { this.tid = tid; }
public String getTname() { return tname; }
public void setTname(String tname) { this.tname = tname; }
public ArrayList getList() { return list; }
public void setList(ArrayList list) { this.list = list; }
}
package dao;
import bean.Teacher;
public interface TeacherDao {
//定义操作方法
//1.定义一个根据老师id查询老师信息(包括对应学生信息)只需要返回老师对象,它包含学生集合
public Teacher getById(int tid);
}
package dao.impl;
import bean.Student;
import bean.Teacher;
import com.mysql.cj.jdbc.Driver;
import dao.TeacherDao;
import java.sql.*;
import java.util.ArrayList;
public class TeacherDaoImpl implements TeacherDao {
@Override
public Teacher getById(int tid) {
//先通过JDBC连接上数据库
Connection conn = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//注册JDBC驱动程序-打开通信通道
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接-连接指定数据库
String userName = "root";
String passWord = "你自己密码";
String url = "jdbc:mysql://localhost:3306/student1?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userName, passWord);
//定义sql,创建预状态通道,进行sql语句的发送
String sql = "select * from student s,teacher t where s.teacherid=t.tid and t.tid=?";
pps = conn.prepareStatement(sql);
//占位符赋值
pps.setInt(1, tid);
//执行sql,返回查询结果集
resultSet = pps.executeQuery();
Teacher teacher = new Teacher();//创建对象,存储tid对应的老师信息,老师只有一个,只创建一次
ArrayList students = new ArrayList<>();//集合,存储该老师对应所有学生
//遍历结果集,取出所查询老师信息及所带的学生信息
while (resultSet.next()) {//一行行读取结果集
teacher.setTid(resultSet.getInt("tid"));
teacher.setTname(resultSet.getString("tname"));
Student student = new Student();//每读取一条记录都需要一个学生对象存储学生信息,所以放在循环里
student.setStuid(resultSet.getInt("stuid"));
student.setSname(resultSet.getString("stuname"));
//将学生存储到集合中
students.add(student);
}
teacher.setList(students);//建立学生和老师之间关系,将学生存储到老师的list集合中
return teacher;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
//释放资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (pps != null) {
try {
pps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return null;
}
}
package test;
import bean.Student;
import bean.Teacher;
import dao.impl.TeacherDaoImpl;
import java.util.ArrayList;
/**
* java操作数据库测试
* 老师-学生 一对多关系
* 查询指定老师信息及该老师带的学生信息
*/
public class Demo1 {
public static void main(String[] args) {
TeacherDaoImpl dao = new TeacherDaoImpl();
Teacher teacher = dao.getById(1);
System.out.println("老师姓名:"+teacher.getTname());
ArrayList studentList = teacher.getList();//获取该老师的学生
for (Student stu : studentList) {
System.out.println("\t 学生姓名:"+stu.getSname());
}
}
}
(学生角度)
package bean;
/**
* student表对应的java实体类
* 学生-老师 多对一
* 站在学生角度:在多方创建一个存储一方数据的对象,即在学生类中定义一个老师属性。
*/
public class Student2 {
private int stuid;
private String sname;
private Teacher2 teacher;
public int getStuid() { return stuid; }
public void setStuid(int stuid) { this.stuid = stuid; }
public String getSname() { return sname; }
public void setSname(String sname) { this.sname = sname; }
public Teacher2 getTeacher() { return teacher; }
public void setTeacher(Teacher2 teacher) { this.teacher = teacher; }
}
package bean;
import java.util.ArrayList;
/**
* teacher表对应的实体类
* 学生-老师 多对一
*/
public class Teacher2 {
private int tid;
private String tname;
public int getTid() { return tid; }
public void setTid(int tid) { this.tid = tid; }
public String getTname() { return tname; }
public void setTname(String tname) { this.tname = tname; }
}
package dao;
import bean.Student2;
import java.util.ArrayList;
public interface StudentDao {
//查询所有学生信息包括对应老师信息
public ArrayList getAll();
}
学生接口实现类:
package dao.impl;
import bean.Student2;
import bean.Teacher2;
import dao.StudentDao;
import java.sql.*;
import java.util.ArrayList;
public class StudentDaoImpl implements StudentDao {
//查询所有学生信息包括对应老师信息(将老师信息放入到学生中)
@Override
public ArrayList getAll() {
Connection conn = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");//加载驱动
String userid = "root";
String pass = "你自己密码";
String url = "jdbc:mysql://localhost:3306/student1?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userid, pass);//获取连接
String sql = "select * from student s,teacher t where s.teacherid=t.tid";//定义sql
pps = conn.prepareStatement(sql);//创建预状态通道,提交sql
resultSet = pps.executeQuery();//返回结果集
ArrayList students = new ArrayList<>();//存储学生的集合,每个学生中包含一位老师
while (resultSet.next()) { //一行行读取数据
Student2 student2 = new Student2();//将每一行中学生信息存入一个学生对象
student2.setStuid(resultSet.getInt("stuid"));
student2.setSname(resultSet.getString("stuname"));
Teacher2 teacher2 = new Teacher2();//每一行中老师信息存入一个老师对象
teacher2.setTid(resultSet.getInt("teacherid"));
teacher2.setTname(resultSet.getString("tname"));
//建立学生和老师之间关系:即将老师存入学生中
student2.setTeacher(teacher2);
students.add(student2);//学生放入集合中
}
return students;//返回学生集合(里面包含了老师)
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
//释放资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (pps != null) {
try {
pps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return null;
}
}
测试
package test;
import bean.Student2;
import dao.impl.StudentDaoImpl;
import java.util.ArrayList;
/**
* java操作数据库测试
* * 学生-老师 多对一关系
* * 查询所有的学生(包含老师的信息
*/
public class Demo2 {
public static void main(String[] args) {
StudentDaoImpl dao = new StudentDaoImpl();//操作数据库
ArrayList students = dao.getAll();
for (Student2 stu:students){
System.out.println(stu.getSname()+","+stu.getTeacher().getTname());
}
}
}
需求:
实现:
数据表:
CREATE TABLE `wife` (
`wifeid` int NOT NULL AUTO_INCREMENT,
`wifename` varchar(255) DEFAULT NULL,
`hid` int DEFAULT NULL,
PRIMARY KEY (`wifeid`),
UNIQUE KEY `uq_wife_hid` (`hid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `wife` VALUES ('1', '孙俪', '1');
CREATE TABLE `husband` (
`husid` int NOT NULL AUTO_INCREMENT,
`husname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`husid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `husband` VALUES ('1', '邓超');
package bean;
/**
* 妻子-丈夫 双向一对一关系
* 双方实体类各保存对方的信息,达到双向一对一效果
*/
public class Wife {
//Wife实体类需要的属性(包含Husband)
private int wifeId;
private String wifeName;
private Husband husband;
public int getWifeId() { return wifeId; }
public void setWifeId(int wifeId) { this.wifeId = wifeId; }
public String getWifeName() { return wifeName; }
public void setWifeName(String wifeName) { this.wifeName = wifeName; }
public Husband getHusband() { return husband; }
public void setHusband(Husband husband) { this.husband = husband; }
}
package bean;
/**
* 丈夫-妻子 双向一对一关系
* 双方实体类各保存对方的信息,达到双向一对一效果
*/
public class Husband {
private int husid;
private String husName;
private Wife wife;
public int getHusid() { return husid; }
public void setHusid(int husid) { this.husid = husid; }
public String getHusName() { return husName; }
public void setHusName(String husName) { this.husName = husName;}
public Wife getWife() { return wife; }
public void setWife(Wife wife) { this.wife = wife; }
}
接口:这里就写一个接口,妻子丈夫方法放在一起
package dao;
import bean.Husband;
import bean.Wife;
public interface wifeDao {
/**
* 查询妻子信息(要求包含丈夫信息)
* @param wid
* @return
*/
public Wife getWife(int wid);
/**
* 查询丈夫信息(要求包含妻子信息)
* @param hid
* @return
*/
public Husband getHusband(int hid);
}
接口实现类:
package dao.impl;
import bean.Husband;
import bean.Wife;
import dao.wifeDao;
import java.sql.*;
public class WifeDaoImpl implements wifeDao {
static Connection conn = null;
static PreparedStatement pps = null;
static ResultSet resultSet = null;
/**
* 查询妻子信息(要求包含丈夫信息)--即将丈夫对象作为妻子对象的成员变量
* @param wid
* @return
*/
@Override
public Wife getWife(int wid) {
String sql="select * from wife w,husband h where w.hid=h.husid and w.wifeid=?";//定义sql
try{
conn = WifeDaoImpl.getConnection();//通过封装的静态方法获取连接
pps = conn.prepareStatement(sql);//创建预状态通道,提交sql
pps.setInt(1,wid); //传递的参数作为占位符值-要查找的wife的id
resultSet = pps.executeQuery();//执行sql,获取到要查询的结果
Wife wife = new Wife();//将查询到的结果存入java对象,将该对象放在外面是因为它只有一个并且要被返回
while(resultSet.next()){ //只有一条记录
wife.setWifeId(resultSet.getInt("wifeid"));
wife.setWifeName(resultSet.getString("wifename"));
Husband husband = new Husband();
husband.setHusid(resultSet.getInt("husid"));
husband.setHusName(resultSet.getString("husname"));
//建立妻子与丈夫关系:将丈夫对象放入妻子对象中
wife.setHusband(husband);
}
return wife;//返回查询结果
}catch (SQLException throwables){
throwables.printStackTrace();
}finally {
WifeDaoImpl.close(resultSet,pps,conn);
}
return null;//若出现异常,返回Null
}
/**
* 查询丈夫信息(要求包含妻子信息):
* @param hid
* @return
*/
@Override
public Husband getHusband(int hid) {
String sql="select * from wife w, husband h where w.hid=h.husid and h.husid=? ";//定义sql
try{
conn = WifeDaoImpl.getConnection();//获取连接
pps = conn.prepareStatement(sql);//预状态通道,提交sql到数据库
pps.setInt(1,hid);//占位符赋值
resultSet = pps.executeQuery();//执行sql,获取查询结果集(这里只有一条记录)
Husband husband = new Husband();//将查询结果存入该对象并返回
while(resultSet.next()){
husband.setHusid(resultSet.getInt("husid"));
husband.setHusName(resultSet.getString("husname"));
Wife wife = new Wife();
wife.setWifeId(resultSet.getInt("wifeid"));
wife.setWifeName(resultSet.getString("wifename"));
//建立丈夫与妻子一对一关系 即将妻子对象放入丈夫对象中,返回丈夫对象
husband.setWife(wife);
return husband; //没有异常情况下返回
}
}catch (SQLException throwables){
throwables.printStackTrace();
}finally {
WifeDaoImpl.close(resultSet,pps,conn);
}
return null;
}
/**
* 抽取 获取连接conn
* @return
*/
private static Connection getConnection(){
try {
//注册JDBC驱动程序-打开通信通道
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接-连接指定数据库
String userName = "root";
String passWord = "你自己密码";
String url = "jdbc:mysql://localhost:3306/student1?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userName, passWord);
return conn;
}catch (ClassNotFoundException e){
e.printStackTrace();
}catch (SQLException throwables){
throwables.printStackTrace();
}
return null;
}
/**
* 抽取关闭资源
* @param resultSet
* @param pps
* @param conn
*/
private static void close(ResultSet resultSet,PreparedStatement pps,Connection conn){
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (pps!=null){
try {
pps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
测试类
package test;
import bean.Husband;
import bean.Wife;
import dao.impl.WifeDaoImpl;
/**
* java操作数据库
* 妻子-丈夫 双向一对一关系
*/
public class Demo3 {
public static void main(String[] args) {
WifeDaoImpl wifeDao = new WifeDaoImpl();
Wife wife = wifeDao.getWife(1);//dao查询1号妻子信息(包含其丈夫信息)
System.out.println(wife.getWifeName()+"的丈夫是:"+wife.getHusband().getHusName());
Husband husband = wifeDao.getHusband(1);//dao查询1号丈夫信息(包含其妻子信息)
System.out.println(husband.getHusName()+"的妻子是:"+husband.getWife().getWifeName());
}
}
需求:
实现:
数据表
CREATE TABLE `middle` (
`middleid` int(11) NOT NULL AUTO_INCREMENT,
`stuid` int(11) DEFAULT NULL,
`subid` int(11) DEFAULT NULL,
PRIMARY KEY (`middleid`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of middle
-- ----------------------------
INSERT INTO `middle` VALUES ('1', '1', '1');
INSERT INTO `middle` VALUES ('2', '1', '2');
INSERT INTO `middle` VALUES ('3', '1', '3');
INSERT INTO `middle` VALUES ('4', '1', '5');
INSERT INTO `middle` VALUES ('5', '2', '2');
INSERT INTO `middle` VALUES ('6', '3', '2');
INSERT INTO `middle` VALUES ('7', '4', '2');
INSERT INTO `middle` VALUES ('8', '5', '2');
INSERT INTO `middle` VALUES ('9', '6', '2');
-- ----------------------------
-- Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`stuid` int(11) NOT NULL AUTO_INCREMENT,
`stuname` varchar(255) DEFAULT NULL,
`teacherid` int(11) DEFAULT NULL,
PRIMARY KEY (`stuid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', '张三', '3');
INSERT INTO `student` VALUES ('2', '李四', '1');
INSERT INTO `student` VALUES ('3', '王五', '3');
INSERT INTO `student` VALUES ('4', '赵六', '1');
INSERT INTO `student` VALUES ('5', '花花', '1');
INSERT INTO `student` VALUES ('6', '潇潇', '2');
-- ----------------------------
-- Table structure for `subject`
-- ----------------------------
DROP TABLE IF EXISTS `subject`;
CREATE TABLE `subject` (
`subid` int(11) NOT NULL AUTO_INCREMENT,
`subname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`subid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of subject
-- ----------------------------
INSERT INTO `subject` VALUES ('1', 'java');
INSERT INTO `subject` VALUES ('2', 'ui');
INSERT INTO `subject` VALUES ('3', 'h5');
INSERT INTO `subject` VALUES ('4', 'c');
INSERT INTO `subject` VALUES ('5', 'c++');
INSERT INTO `subject` VALUES ('6', 'c#');
实体类:
package bean;
import java.util.List;
public class Subject3 {
private int subid;
private String subname;
private List stulist;//定义list集合存放学习这个科目的学生
public int getSubid() { return subid; }
public void setSubid(int subid) { this.subid = subid; }
public String getSubname() { return subname; }
public void setSubname(String subname) { this.subname = subname; }
public List getStulist() { return stulist; }
public void setStulist(List stulist) { this.stulist = stulist; }
}
package bean;
import java.util.List;
public class Student3 {
private int stuid;
private String stuname;
//外键列一般不生成属性
//private int teacherid;
private Teacher teacher;//定义这个学生对应的老师
private Listsubjects;//定义集合存放一个学生对应的多个科目
public int getStuid() { return stuid; }
public void setStuid(int stuid) { this.stuid = stuid; }
public String getStuname() { return stuname; }
public void setStuname(String stuname) { this.stuname = stuname; }
public Teacher getTeacher() { return teacher; }
public void setTeacher(Teacher teacher) { this.teacher = teacher; }
public List getSubjects() { return subjects; }
public void setSubjects(List subjects) { this.subjects = subjects; }
}
接口:没有分开定义
package dao;
import bean.Student3;
import bean.Subject3;
public interface Subject3Dao {
/**
* 查询某个学生信息(包含其所学科目)
* 返回学生对象,学生中的subjects集合存放该学生的科目
* @param id
* @return
*/
public Student3 findById(int id);
/**
* 查询某个科目以及对应的学生姓名
* 返回科目对象,科目中定义了stulist集合存放该科目对应的学生
* @param id
* @return
*/
public Subject3 findBySubId(int id);
}
接口实现类:
package dao.impl;
import bean.Student3;
import bean.Subject3;
import dao.Subject3Dao;
import java.sql.*;
import java.util.ArrayList;
/**
* dao层操作数据--先来连接数据库-执行sql获取结果集-存入java对象--返回该对象
*/
public class Subject3DaoImpl implements Subject3Dao {
static Connection conn=null;
static PreparedStatement pps=null;
static ResultSet resultSet=null;
/**
* 查询某个学生信息(包括查询出所学科目)
* @param id
* @return
*/
@Override
public Student3 findById(int id) {
try {
//获取连接
conn = Subject3DaoImpl.getConnection();
//定义sql
String sql="select * from student st,subject su,middle m where st.stuid=m.stuid and m.subid=su.subid and st.stuid=?";
//创建预状态通道,提交sql
pps = conn.prepareStatement(sql);
//占位符赋值
pps.setInt(1,id);
//执行sql
resultSet = pps.executeQuery();
//因为要返回学生,且查询的学生只有一个,不要在循环中创建对象,学科就需要,一个学生有多个科目
Student3 stu3 = new Student3();
ArrayList subjects = new ArrayList<>();//集合存放科目对象
while(resultSet.next()){//便利每一条记录,将信息分别存入对应的对象
stu3.setStuid(resultSet.getInt("stuid"));
stu3.setStuname(resultSet.getString("stuname"));
//将科目相关信息存入到科目对象中
Subject3 sub3 = new Subject3();
sub3.setSubid(resultSet.getInt("subid"));
sub3.setSubname(resultSet.getString("subname"));
//将科目对象装入到集合中
subjects.add(sub3);
}
//建立学生与科目之间的关系--将科目集合赋值到学生的集合属性中
stu3.setSubjects(subjects);
return stu3;
}catch (SQLException throwables){
throwables.printStackTrace();
}finally {
Subject3DaoImpl.chose(resultSet,conn,pps);
}
return null;//上述异常,输出null
}
/**
* 查询某个科目以及对应的学生姓名
* @param id
* @return
*/
@Override
public Subject3 findBySubId(int id) {
try{
conn = Subject3DaoImpl.getConnection();
String sql="select * from subject su,middle m,student st where su.subid=m.subid and m.stuid=st.stuid and su.subid=?";
pps = conn.prepareStatement(sql);
pps.setInt(1,id);
resultSet = pps.executeQuery();
Subject3 subject3 = new Subject3();//查询科目只有一个,且要返回,不放入循环
ArrayList students = new ArrayList<>();//创建集合,存放该科目对应的所有学生
while(resultSet.next()){
subject3.setSubid(resultSet.getInt("subid"));//将科目信息存入对象
subject3.setSubname(resultSet.getString("subname"));
Student3 student3 = new Student3();//将学生信息存入对象
student3.setStuid(resultSet.getInt("stuid"));
student3.setStuname(resultSet.getString("stuname"));
students.add(student3);//学生装入集合
}
subject3.setStulist(students);//将学生集合存入科目中
return subject3;
}catch (SQLException throwables){
throwables.printStackTrace();
}finally {
Subject3DaoImpl.chose(resultSet,conn,pps);
}
return null;
}
/**
* 抽取 获取连接的方法
* @return
*/
private static Connection getConnection(){
try{
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String userName="root";
String passWord="你自己密码";
String url="jdbc:mysql://localhost:3306/student_subject?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userName, passWord);
return conn;
}catch (ClassNotFoundException e){
e.printStackTrace();
} catch (SQLException throwables){
throwables.printStackTrace();
}
return null;//出现异常,返回null
}
private static void chose(ResultSet resultSet,Connection conn,PreparedStatement pps) {
.......
}
}
测试类
package test;
import bean.Student3;
import bean.Subject3;
import dao.impl.Subject3DaoImpl;
import java.util.List;
/**
* 多对多(科目-学生)
*/
public class Demo4 {
public static void main(String[] args) {
Subject3DaoImpl dao = new Subject3DaoImpl();
//查询某个学生信息(查询出所学科目)
Student3 stu = dao.findById(5);
System.out.println("姓名:"+stu.getStuname());
List subjects = stu.getSubjects();
for (Subject3 sub:subjects) {
System.out.println("\t"+sub.getSubname());
}
///查询某个科目以及对应的学生姓名
Subject3 sub = dao.findBySubId(1);
System.out.println("所查科目:"+sub.getSubname());
List stulist = sub.getStulist();
for (Student3 student3:stulist){
System.out.println("\t"+student3.getStuname());
}
}
}
事务开始于
事务结束于
1. 原⼦性(Atomicity)
2. ⼀致性(Consistency)
3. 隔离性(Isolation)
事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
4. 持久性(Duration)
conn.commit( );
conn.rollback( );
try{
//Assume a valid connection object conn
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
String SQL = "INSERT INTO Employees values (106, 20, 'Rita', 'Tez')";
stmt.executeUpdate(SQL);
//Submit a malformed SQL statement that breaks
String SQL = "INSERTED IN Employees VALUES (107, 22, 'Sita', 'Singh')";
stmt.executeUpdate(SQL);
// If there is no error.
conn.commit();
}catch(SQLException se){
// If there is any error.
conn.rollback();
}
setSavepoint(String savepointName):定义新的保存点。它还返回一个Savepoint对象。
releaseSavepoint(Savepoint savepointName):删除保存点。它需要一个Savepoint 对象作为参数。此对象通常是由setSavepoint()方法生成的保存点。
try{
//Assume a valid connection object conn
conn.setAutoCommit(false);//开启手动提交模式
Statement stmt = conn.createStatement();
Savepoint savepoint1 = conn.setSavepoint("Savepoint1");//设置回滚保存点
String SQL = "INSERT INTO Employees VALUES (106, 20, 'Rita', 'Tez')";
stmt.executeUpdate(SQL);
String SQL = "INSERTED IN Employees VALUES (107, 22, 'Sita', 'Tez')";
stmt.executeUpdate(SQL);
conn.commit(); //提交
}catch(SQLException se){
conn.rollback(savepoint1); //出现异常,则回滚到保存点
}
转账流程:
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pps = null;
Savepoint sp = null;
try {
//0.导入JDBC API(jdbc jar包),程序可以调用这些API
//1.注册JDBC驱动程序--打开程序与数据库的通信通道
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接--即通过连接地址url,用户名和密码连接上数据库student
String userName = "root";
String passWord = "你自己密码";
String url = "jdbc:mysql://localhost:3306/emp_dept_sala?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userName, passWord);
conn.setAutoCommit(false);//开启 手动提交事务 模式,执行一组sql语句
sp = conn.setSavepoint("回滚保存点1");//设置回滚保存点
//3.执行sql语句--创建预状态通道preparedStatement,执行sql语句的发送
pps = conn.prepareStatement("update money set usermoney=usermoney-1000 where userid=?");
pps.setInt(1, 1);//占位符赋值
int result = pps.executeUpdate();
if (result > 0) System.out.println("转账成功");
pps = conn.prepareStatement("update money set usermoney=usermoney+1000 where userid=?");
pps.setInt(1, 2);
int result1 = pps.executeUpdate();
if (result1 > 0) System.out.println("到账成功");
conn.commit();//以上没有异常,则提交事务
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback(sp);//上面出现异常,则回滚到保存点,事务结束
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}finally {
.......
}
}
package demo5;
import java.sql.*;
public class Demo {
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
//0.导入JDBC API(jdbc jar包),程序可以调用这些API
//1.注册JDBC驱动程序--打开程序与数据库的通信通道
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接--即通过连接地址url,用户名和密码连接上数据库student
String userName = "root";
String passWord = "你自己密码";
String url = "jdbc:mysql://localhost:3306/student1?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userName, passWord);
conn.setAutoCommit(false);//开启 手动提交事务 模式,执行一组sql语句
statement = conn.createStatement();//创建状态通道
String sql1="insert into teacher values(null,'张三a')";//tid自增
statement.addBatch(sql1);//添加sql到批处理
String sql2="insert into teacher values(null,'张三b')";
statement.addBatch(sql2);//添加sql到批处理
String sql3="insert into teacher values(null,'张三c')";
statement.addBatch(sql3);//添加sql到批处理
int[] ints = statement.executeBatch();//数组每一个元素对应每条sql影响的行数
conn.commit();//提交事务,数据保存到数据库
for (int i = 0; i < ints.length;) {
if (ints[i]>0) System.out.println("第"+(++i)+"条sql语句插入成功");
}
}catch (Exception e){
e.printStackTrace();//若上述有一个地方异常,则回滚所有sql操作
try {
System.out.println("异常,事务回滚了");
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}finally {
//5.关闭资源,需要判空
.............
}
}
}
public class Demo1 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pps = null;
try {
//0.导入JDBC API(jdbc jar包),程序可以调用这些API
//1.注册JDBC驱动程序--打开程序与数据库的通信通道
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接--即通过连接地址url,用户名和密码连接上数据库student
String userName = "root";
String passWord = "你自己密码";
String url = "jdbc:mysql://localhost:3306/student1?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userName, passWord);
conn.setAutoCommit(false);//开启 手动提交事务 模式,执行一组sql语句
pps = conn.prepareStatement("insert into teacher values(null,?)");//创建预状态通道
pps.setString(1,"王五a"); //占位符赋值
pps.addBatch(); //添加sql到批处理
pps.setString(1,"王五b");
pps.addBatch();
pps.setString(1,"王五c");
pps.addBatch();
int[] ints = pps.executeBatch();//数组每一个元素对应每条sql影响的行数
conn.commit();//提交事务,数据保存到数据库
for (int i = 0; i < ints.length;) {
if (ints[i]>0) System.out.println("第"+(++i)+"条sql语句插入成功");
}
}catch (Exception e){
e.printStackTrace();//若上述有一个地方异常,则回滚所有sql操作
try {
System.out.println("异常,事务回滚了");
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}finally {
............
}
}
}
try {
Class.forName("com.mysql.cj.jdbc.Driver");//1.加载驱动
String userid = "root";
String pass = "你自己密码";
String url = "jdbc:mysql://localhost:3306/student1?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userid, pass);//2.获取连接
String sql = "select * from student";//定义sql
pps = conn.prepareStatement(sql);//3.创建预状态通道,提交sql
resultSet = pps.executeQuery();//4.执行sql,返回结果集
ArrayList students = new ArrayList<>();//存储学生的集合
while (resultSet.next()) { //一行行读取数据
Student student2 = new Student();//将每一行中学生信息存入一个学生对象
student2.setStuid(resultSet.getInt("stuid"));
student2.setSname(resultSet.getString("stuname"));
students.add(student2);//学生放入集合中
}
return students;//返回学生集合
}
业务逻辑
1.获取数据库查询结果集中所有列名(字段)
2.反射得到Student实体类中所有的方法
3.遍历结果集,取出各自的信息
3.1第一层循环,遍历列
装饰列名实现与实体类中属性的setter方法一致
第二层循环,遍历Student实体类中所有的方法名,找到与当前装饰列名相同的setter方法
给stu对象通过指定的set方法赋值,值是当前记录的当前列的值
当前记录的当前这个列内容已经set完成,break;
3.2当前记录所有列的内容都set到stu对象,stu装入集合,继续结果集下一条记录
4.返回学生集合
数据表
CREATE TABLE `student` (
`stuid` int NOT NULL AUTO_INCREMENT,
`stuname` varchar(255) DEFAULT NULL,
`teacherid` int DEFAULT NULL,
PRIMARY KEY (`stuid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
bean包的实体类
package bean;
/**
* 数据库student1中student表对应的java实体类
* 切记:实体类属性要与表字段命名一致
*/
public class Student {
private int stuid;
private String stuname;
private int teacherid;
public int getStuid() {return stuid; }
public void setStuid(int stuid) { this.stuid = stuid; }
public String getStuname() { return stuname; }
public void setStuname(String sname) { this.stuname = sname; }
public int getTeacherid() { return teacherid; }
public void setTeacherid(int teacherid) { this.teacherid = teacherid; }
}
dao层接口
package dao;
import bean.Student;
import java.util.ArrayList;
import java.util.List;
public interface StudentDao {
/**
* 查询数据表student所有学生信息,使用反射技术实现,
* 参数传递Student实体类的字节码对象
* @return
*/
public List getAllStudent(Class cla);
}
dao层接口实现类
package dao.Impl;
import bean.Student;
import dao.StudentDao;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class StudentDaoImpl implements StudentDao {
/**
* 查询所有学生信息
* 使用反射技术动态获取实体类Student中setter方法
* @return
*/
@Override
public List getAllStudent(Class cla) {
Connection conn = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");//1.加载驱动
String userid = "root";
String pass = "你自己密码";
String url = "jdbc:mysql://localhost:3306/student1?serverTimezone=UTC";
conn = DriverManager.getConnection(url, userid, pass);//2.获取连接
String sql = "select * from student";//定义sql
pps = conn.prepareStatement(sql);//3.创建预状态通道,提交sql
resultSet = pps.executeQuery();//4.执行sql,返回结果集
List students = new ArrayList();//存储学生的集合
//反射技术处理结果集
//通过反射技术让结果集自动匹配实体类的setter方法
//1.获取数据库查询结果集中所有列名(字段)
ResultSetMetaData metaData = resultSet.getMetaData();//得到结果集的结构信息,比如字段数、字段名等
int columnCount = metaData.getColumnCount();//得到列数
String[] columnNames = new String[columnCount];//创建字符串数组准备存入列名
for (int i = 0; i < columnNames.length; i++) {
columnNames[i]=metaData.getColumnName(i+1);//依次从metaData中获取列名存入数组,从第1列开始
System.out.println("columnname="+columnNames[i]);
}
//2.得到Student实体类中所有的方法
Method[] declaredMethods = cla.getDeclaredMethods();
//3.便利结果集,取出各自的信息
while(resultSet.next()){
try {
Object stu = cla.newInstance();//创建对象,准备存储结果集每条记录信息
for(String columnName: columnNames){//遍历列
//装饰列名实现与实体类中属性的setter方法一致,(规范:表名与类名要同,列名与属性名要同)
String methodName="set"+columnName;//比如列名stuid,装饰成了setstuid
for(Method declaredMethod:declaredMethods){
//遍历Student实体类中所有的方法名,找到与当前装饰列名相同的方法名,比如找到setStuid与装饰的setstuid同
if (declaredMethod.getName().equalsIgnoreCase(methodName)){
//给stu对象通过指定的set方法赋值,值是当前记录的当前列的值,不知道列类型,都视为Object
declaredMethod.invoke(stu,resultSet.getObject(columnName));
break; //表示当前记录的当前这个列已经set完成,当前记录还有好多列等着循环,结果集还有好多记录等着循环
}
}
}
//当前记录所有列的内容都set到stu对象,stu装入集合,继续结果集下一条记录
students.add(stu);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return students;//返回学生集合
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
//释放资源
.............
}
return null;
}
}
测试类
package test;
import bean.Student;
import dao.Impl.StudentDaoImpl;
import java.util.List;
public class Demo {
public static void main(String[] args) {
StudentDaoImpl dao = new StudentDaoImpl();
List allStudent = dao.getAllStudent(Student.class);
for (Student student:allStudent){
System.out.println(student.getStuid()+","+student.getStuname()+","+student.getTeacherid());
}
}
}
加载属性文件
方式一:类加载器
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/student1?serverTimezone=UTC
uname=root
upass=你自己密码
package util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.List;
import java.util.Properties;
public class DBUtils {
//1.定义变量
private Connection connection; //连接
private PreparedStatement pps; //预状态通道
private ResultSet resultSet; //结果集
private int count; //存储受影响的行数
private static String driverName;//驱动程序名称
private static String userName;//数据库用户名
private static String userPass;//数据库密码
private static String url;//数据库连接地址
//2.加载驱动 (只需要加载一次,放入静态代码块中),使用配置文件
static{
try {
InputStream is = DBUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties pro = new Properties();
pro.load(is); //配置文件信息已加载进pro集合
driverName = pro.getProperty("driver");//从pro集合获取信息
userName = pro.getProperty("uname");
userPass = pro.getProperty("upass");
url = pro.getProperty("url");
Class.forName(driverName);//加载驱动
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//3.获得连接
protected Connection getConnection(){
//protected方法受保护,特点能被子类访问,防止任意一个类调用该方法
try {
connection = DriverManager.getConnection(url, userName, userPass);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
//4.得到预状态通道
protected PreparedStatement getPps(String sql){
try {
pps = getConnection().prepareStatement(sql);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return pps;
}
//5.绑定参数(sql占位符赋值),传递过来一个存放参数的list集合
protected void param(List list){
if (list!=null&&list.size()>0){//先判空
for (int i = 0; i < list.size(); i++) {
try {
pps.setObject(i+1,list.get(i));//给pps每个占位符赋值
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
//6.执行sql,(增删改)
protected int update(String sql,List list){
getPps(sql);//获取预状态通道pps
param(list);//给pps每个占位符赋值(绑定参数)
try {
count=pps.executeUpdate();//执行,返回影响的行数
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return count;
}
//7.执行sql,(查询)
protected ResultSet query(String sql,List list){
getPps(sql);//获取预状态通道pps
param(list);//给pps每个占位符赋值(绑定参数)
try {
resultSet = pps.executeQuery();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return resultSet;
}
//8.关闭资源
protected void closeAll(){
...........
}
}
方式2:使用ResourceBundle访问properties文件
static{
//参数只写属性文件名即可,不需要写后缀
ResourceBundle bundle = ResourceBundle.getBundle("db");
driverName = bundle.getString("driver");
url = bundle.getString("url");
userName= bundle.getString(uname");
userPass = bundle.getString("upass");
}
public class Pool{static LinkedList list = new LinkedList();
static{
for (int i = 0; i < 10; i++) {
Connection connection = JDBCUtils.newInstance().getConnection();
list.add(connection);
}
}
/**
* 从连接池子中获取连接的方式
* @return
*/
public static Connection getConnection(){
if (list.isEmpty()) {
//JDBCUtils类是自定义类,封装了连接数据库的信息代码
Connection connection = JDBCUtils.newInstance().getConnection();
list.addLast(connection);
}
Connection conn = list.removeFirst();
return conn;
}
/**
* 返回到连接池子中
*/
public static void addBack(Connection conn){
if (list.size() >= 10) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
list.addLast(conn); //10
}
}
/**
* 获取连接池子中连接数量的方法
*/
public static int getSize(){
return list.size();
}
}
public class MyConnection implements Connection{
//将被装饰者导入
private Connection conn;
private LinkedList list;
public MyConnection(Connection conn, LinkedList list) {
super();
this.conn = conn;
this.list = list;
}
@Override
public T unwrap(Class iface) throws SQLException {
return conn.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class iface) throws SQLException {
return conn.isWrapperFor(iface);
}
@Override
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return null;
}
@Override
public String nativeSQL(String sql) throws SQLException {
return null;
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException { }
@Override
public boolean getAutoCommit() throws SQLException {
return false;
}
@Overridepublic void commit() throws SQLException {
conn.commit();
}
@Override
public void rollback() throws SQLException {
conn.rollback();
}
@Override
public void close() throws SQLException {
list.addLast(conn);
}
...
}
/**
* 创建一个规范的连接池子
*/
public class DataSourcePool implements DataSource{
static LinkedList list = new LinkedList();
static{
for (int i = 0; i < 10; i++) {
Connection connection = JDBCUtils.newInstance().getConnection();
list.add(connection);
}
}
public static int getSize(){
return list.size();
}
@Override
public Connection getConnection() throws SQLException {
Connection conn = list.removeFirst();
MyConnection conn1 = new MyConnection(conn, list);
return conn1;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {}
@Override
public void setLoginTimeout(int seconds) throws SQLException {}
@Overridepublic int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public T unwrap(Class iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class iface) throws SQLException {
return false;
}
@Override
public Connection getConnection(String username, String password) throws
SQLException {
return null;
}
}
导入相应jar包
@Test
public void testHard() throws SQLException{
// 硬编码 使用DBCP连接池子
BasicDataSource source = new BasicDataSource();
//设置连接的信息
source.setDriverClassName("com.mysql.cj.jdbc.Driver");
source.setUrl("jdbc:mysql://localhost:3306/student1?serverTimezone=UTC");
source.setUsername("root");
source.setPassword("111");
Connection connection = source.getConnection();
String sql = "select * from student";
Statement createStatement = connection.createStatement();
ResultSet executeQuery = createStatement.executeQuery(sql);
while (executeQuery.next()) {
System.out.println(executeQuery.getString(2));
}
connection.close(); //回收
}
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/student1?serverTimezone=UTC
uname=root
upass=你自己密码
#
initialSize=10
#最大连接数量
maxActive=50
#
maxIdle=20
#
minIdle=5
#
maxWait=6000
JDBC_DBCP连接池工具类
package util;
import org.apache.commons.dbcp.BasicDataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.List;
import java.util.Properties;
import java.util.ResourceBundle;
/**
* JDBC_DBCP工具类
*/
public class DBUtils {
//1.定义变量
private Connection connection; //连接
private PreparedStatement pps; //预状态通道
private ResultSet resultSet; //结果集
private int count; //存储受影响的行数
private static String driverName;//驱动程序名称
private static String userName;//数据库用户名
private static String userPass;//数据库密码
private static String url;//数据库连接地址
private static BasicDataSource basicDataSource = new BasicDataSource();//创建一个工具类,加载驱动和获取连接都由它完成
//2.加载驱动 (只需要加载一次,放入静态代码块中),使用ResourceBundle加载本地资源db.properties
static{
//使用ResourceBundle访问本地资源db.properties
ResourceBundle bundle = ResourceBundle.getBundle("db");
driverName = bundle.getString("driver");
url = bundle.getString("url");
userName = bundle.getString("uname");
userPass = bundle.getString("upass");
//BasicDataSource加载驱动和获取连接都由它完成
basicDataSource.setUsername(userName); //设置信息
basicDataSource.setPassword(userPass);
basicDataSource.setUrl(url);
basicDataSource.setDriverClassName(driverName);
}
//3.获得连接
protected Connection getConnection(){
//protected方法受保护,特点能被子类访问,防止任意一个类调用该方法
try {
connection = basicDataSource.getConnection();
//connection = DriverManager.getConnection(url, userName, userPass);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
//4.得到预状态通道
protected PreparedStatement getPps(String sql){
try {
pps = getConnection().prepareStatement(sql);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return pps;
}
//5.绑定参数(sql占位符赋值),传递过来一个存放参数的list集合
protected void param(List list){
if (list!=null&&list.size()>0){//先判空
for (int i = 0; i < list.size(); i++) {
try {
pps.setObject(i+1,list.get(i));//给pps每个占位符赋值
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
//6.执行sql,(增删改)
protected int update(String sql,List list){
getPps(sql);//获取预状态通道pps
param(list);//给pps每个占位符赋值(绑定参数)
try {
count=pps.executeUpdate();//执行,返回影响的行数
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return count;
}
//7.执行sql,(查询)
protected ResultSet query(String sql,List list){
getPps(sql);//获取预状态通道pps
param(list);//给pps每个占位符赋值(绑定参数)
try {
resultSet = pps.executeQuery();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return resultSet;
}
//8.关闭资源
protected void closeAll(){
...............
}
}
2.添加配置文件
com.mysql.cj.jdbc.Driver
jdbc:mysql://localhost:3306/student1?serverTimezone=UTC
root
你自己密码
30000
30
10
30
100
10
200
3.JDBC_C3P0工具类定义
package util;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.ResourceBundle;
/**
* JDBC_C3P0连接池工具类
*/
public class DBUtils {
//1.定义变量
private Connection connection; //连接
private PreparedStatement pps; //预状态通道
private ResultSet resultSet; //结果集
private int count; //存储受影响的行数
private static String driverName;//驱动程序名称
private static String userName;//数据库用户名
private static String userPass;//数据库密码
private static String url;//数据库连接地址
//1.创建一个工具类ComboPooledDataSource,创建时默认加载xml,加载驱动
private static ComboPooledDataSource comboPooledDataSource= new ComboPooledDataSource();
//3.获得连接
protected Connection getConnection(){
//protected方法受保护,特点能被子类访问,防止任意一个类调用该方法
try {
connection = comboPooledDataSource.getConnection();
//connection = basicDataSource.getConnection();
//connection = DriverManager.getConnection(url, userName, userPass);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
//4.得到预状态通道
protected PreparedStatement getPps(String sql){
try {
pps = getConnection().prepareStatement(sql);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return pps;
}
//5.绑定参数(sql占位符赋值),传递过来一个存放参数的list集合
protected void param(List list){
if (list!=null&&list.size()>0){//先判空
for (int i = 0; i < list.size(); i++) {
try {
pps.setObject(i+1,list.get(i));//给pps每个占位符赋值
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
//6.执行sql,(增删改)
protected int update(String sql,List list){
getPps(sql);//获取预状态通道pps
param(list);//给pps每个占位符赋值(绑定参数)
try {
count=pps.executeUpdate();//执行,返回影响的行数
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return count;
}
//7.执行sql,(查询)
protected ResultSet query(String sql,List list){
getPps(sql);//获取预状态通道pps
param(list);//给pps每个占位符赋值(绑定参数)
try {
resultSet = pps.executeQuery();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return resultSet;
}
//8.关闭资源
protected void closeAll(){
try {
if (connection != null) {
connection.close();
}
if (pps != null) {
pps.close();
}
if (resultSet != null) {
resultSet.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
4.JDBC_C3P0连接池工具类的使用
数据表
CREATE TABLE `student` (
`stuid` int NOT NULL AUTO_INCREMENT,
`stuname` varchar(255) DEFAULT NULL,
`teacherid` int DEFAULT NULL,
PRIMARY KEY (`stuid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
bean包实体类
package bean;
public class Student {
private int stuid;
private String sname;
public int getStuid() { return stuid;}
public void setStuid(int stuid) { this.stuid = stuid; }
public String getSname() { return sname; }
public void setSname(String sname) { this.sname = sname;}
}
dao接口
package dao;
import bean.Student;
/**
* 根据id查询学生信息
*/
public interface StudentDao {
public Student getStudentById(int id);
}
dao实现类
package dao.impl;
import bean.Student;
import dao.StudentDao;
import util.DBUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 根据id查询学生信息
* 使用JDBC_C3P0连接池工具类
*/
public class StudentDaoImpl extends DBUtils implements StudentDao {
@Override
public Student getStudentById(int id) {
Student student = null;
try {
student = new Student();
String sql="select * from student where stuid=?";
List list = new ArrayList();
list.add(id);//集合存放占位符
ResultSet rs = query(sql, list);//继承DBUtils,作为它的子类才可以使用它的protected方法
while(rs.next()){
student.setStuid(rs.getInt("stuid"));
student.setSname(rs.getString("stuname"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
closeAll();
}
return student;
}
}
测试类
package test;
import bean.Student;
import dao.impl.StudentDaoImpl;
public class Demo {
public static void main(String[] args) {
StudentDaoImpl dao = new StudentDaoImpl();
Student student = dao.getStudentById(1);
System.out.println(student.getStuid()+":"+student.getSname());
}
}
优势
亚秒级查询
实时数据注入
.可扩展的PB级存储
多环境部署
1.导入jar包
2.配置文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/student1?serverTimezone=UTC
uname=root
upass=密码
#
initialSize=10
#最大连接数量
maxActive=50
#
maxIdle=20
#
minIdle=5
#
maxWait=6000
3.编写工具类
package util;
import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.ResourceBundle;
/**
* JDBC_Druid连接池工具类
*/
public class DBUtils {
//1.定义变量
private Connection connection; //连接
private PreparedStatement pps; //预状态通道
private ResultSet resultSet; //结果集
private int count; //存储受影响的行数
private static String driverName;//驱动程序名称
private static String userName;//数据库用户名
private static String userPass;//数据库密码
private static String url;//数据库连接地址
//创建DruidDataSource(对象)工具类,需要给它设置用户名连接数据库的信息
private static DruidDataSource druidDataSource=new DruidDataSource();
//使用ResourceBundle来读取properties配置文件信息,并赋值给DruidDataSource来加载驱动和获取连接。
static{
ResourceBundle bundle = ResourceBundle.getBundle("db");
driverName = bundle.getString("driver");
userName = bundle.getString("uname");
userPass = bundle.getString("upass");
url = bundle.getString("url");
druidDataSource.setUsername(userName);
druidDataSource.setPassword(userPass);
druidDataSource.setUrl(url);
druidDataSource.setDriverClassName(driverName);
}
//3.获得连接
protected Connection getConnection(){
//protected方法受保护,特点能被子类访问,防止任意一个类调用该方法
try {
connection = druidDataSource.getConnection();
//connection = comboPooledDataSource.getConnection();
//connection = basicDataSource.getConnection();
//connection = DriverManager.getConnection(url, userName, userPass);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
//4.得到预状态通道
protected PreparedStatement getPps(String sql){
try {
pps = getConnection().prepareStatement(sql);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return pps;
}
//5.绑定参数(sql占位符赋值),传递过来一个存放参数的list集合
protected void param(List list){
if (list!=null&&list.size()>0){//先判空
for (int i = 0; i < list.size(); i++) {
try {
pps.setObject(i+1,list.get(i));//给pps每个占位符赋值
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
//6.执行sql,(增删改)
protected int update(String sql,List list){
getPps(sql);//获取预状态通道pps
param(list);//给pps每个占位符赋值(绑定参数)
try {
count=pps.executeUpdate();//执行,返回影响的行数
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return count;
}
//7.执行sql,(查询)
protected ResultSet query(String sql,List list){
getPps(sql);//获取预状态通道pps
param(list);//给pps每个占位符赋值(绑定参数)
try {
resultSet = pps.executeQuery();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return resultSet;
}
//8.关闭资源
protected void closeAll(){
try {
if (connection != null) {
connection.close();
}
if (pps != null) {
pps.close();
}
if (resultSet != null) {
resultSet.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
/**
* 阿里的数据库连接池 性能最好的
* Druid
* */
public class DruidUtils {
//声明连接池对象
private static DruidDataSource ds;
static{
///实例化数据库连接池对象
ds=new DruidDataSource();
//实例化配置对象
Properties properties=new Properties();
try {
//加载配置文件内容
properties.load(DruidUtils.class.getResourceAsStream("dbcpconfig.properties"));
//设置驱动类全称
ds.setDriverClassName(properties.getProperty("driverClassName"));
//设置连接的数据库
ds.setUrl(properties.getProperty("url"));
//设置用户名
ds.setUsername(properties.getProperty("username"));
//设置密码
ds.setPassword(properties.getProperty("password"));
//设置最大连接数量
ds.setMaxActive(Integer.parseInt(properties.getProperty("maxActive")));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取连接对象
public static Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
package yhp.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import javax.xml.transform.Result;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DruidUtil {
private static DataSource ds;
static{
try {
Properties ppt = new Properties();
ppt.load(DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(ppt);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从连接池中取出一个连接给用户
* @return
*/
public static Connection getConnection(){
try {
return ds.getConnection();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
public static void close(Connection conn, Statement state, ResultSet rs){
if (rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (state!=null){
try {
state.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
MySQL基本使用及单表的增删改查语句
https://blog.csdn.net/qq_40454863/article/details/113809607
常用SQL语句练习整理
https://blog.csdn.net/qq_40454863/article/details/113925975
MySQL高级使用--事务详解
https://blog.csdn.net/qq_40454863/article/details/113899837
数据库的设计、表的约束(完整性)、多表设计与查询
https://blog.csdn.net/qq_40454863/article/details/114067770