JDBC学习
JDBC结构图
1.JDBC简介
Java数据库连接,(Java Database Connectivity,简称JDBC),是Java语言用来规范客户端程序访问并操作数据库的接口, JDBC接口是一套class文件,由SUM公司负责制定JDBC的规范。
JDBC作为规范与各大数据库连接
1.1 学习JDBC数据库
-- 里面有外键,但我不会使用到
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`studentName` varchar(20) NOT NULL COMMENT '姓名',
`password` varchar(50) NOT NULL COMMENT '密码',
`birthday` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '生日',
`classID` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `class_id` (`classID`),
CONSTRAINT `class_id` FOREIGN KEY (`classID`) REFERENCES `class` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', '张三', 'e10adc3949ba59abbe56e057f20f883e', '2021-02-01 00:00:00', '1');
INSERT INTO `student` VALUES ('2', '张于', 'ffe7a019bc8c991d28b894b9aaac2ff7', '2022-03-08 09:29:15', '3');
INSERT INTO `student` VALUES ('3', '吉吉', '5bd2026f128662763c532f2f4b6f2476', '2022-03-08 10:07:46', '2');
INSERT INTO `student` VALUES ('4', '王五', '678987', '2022-09-16 23:50:53', '1');
INSERT INTO `student` VALUES ('5', '李四', '123456', '2022-09-17 00:00:00', '2');
INSERT INTO `student` VALUES ('6', '李四', '123456', '2022-09-17 00:00:00', '2');
2.JDBC使用步骤
1.注册驱动 2.加载数据库驱动,使用 DriverManager 获取连接对象 3.使用 Connection 创建 PreparedStatement 语句对象 4.设置 SQL 语句中的参数值,执行 SQL 语句 5.操作结果集 6.回收数据库资源,包括关闭 ResultSet、Statement 和 Connection 等资源
JDBC简单实例
public class JDBCSelectTest {
// 主启动类
public static void main(String[] args) throws Exception {
jdbcStep();
}
/**
* JDBC简单实现步骤
* @throws Exception 异常处理
*/
public static void jdbcStep() throws Exception {
// 1.注册驱动,注意mysql5驱动不一样,是com.mysql.jdbc.Driver
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.创建连接对象
Connection connection= DriverManager
.getConnection("jdbc:mysql://localhost:3306/sql_study?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"
,"root","123456");
// 3.创建预编译器PreparedStatement,(Statement存储简单SQL注入,没有PreparedStatement安全)
String sql="select * from student where id=?";
PreparedStatement ps=connection.prepareStatement(sql);
ps.setObject(1,1);
// 4.执行SQL,获取结果集
ResultSet rs = ps.executeQuery();
// 5.处理结果集
System.out.println(rs.next()?"有结果值":"没有结果值!");
// 6.释放资源
connection.close();
}
}
3.数据库的增删查改
增删查改
/**
* 创建一个Connection
* @return connection
*/
public static Connection getConnection() {
Connection connection=null;
try{
// 1.注册驱动,注意mysql5驱动不一样,是com.mysql.jdbc.Driver
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.创建连接对象
connection= DriverManager
.getConnection("jdbc:mysql://localhost:3306/sql_study?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"
,"root","123456");
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
/**
* 添加学生
* @param student 学生对象
*/
public static void addStudent(Student student){
String sql="insert into student value(default,?,?,?,?)";
try{
PreparedStatement ps=getConnection().prepareStatement(sql);
ps.setObject(1,student.getStudentName());
ps.setObject(2,student.getPassword());
ps.setObject(3,student.getBirthday());
ps.setObject(4,student.getClassID());
System.out.println(ps.executeUpdate()>0?"添加成功":"添加失败");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 更新学生
*/
public static void updateStudent(){
String sql="update student set studentName=? where id=?";
try{
PreparedStatement ps=getConnection().prepareStatement(sql);
ps.setObject(1,"空空");
ps.setObject(2,5);
System.out.println(ps.executeUpdate()>0?"更新成功":"更新失败");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 删除学生
* @param id 学生id
*/
public static void deleteStudent(int id){
String sql="delete from student where id=?";
try{
PreparedStatement ps=getConnection().prepareStatement(sql);
ps.setObject(1,id);
System.out.println(ps.executeUpdate()>0?"删除成功":"删除失败");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 查询学生
* @param name 学生名字
* @param password 学生密码
*/
public static void selectStudent(String name,String password){
String sql="select * from student where studentName=? and password=?";
try{
PreparedStatement ps=getConnection().prepareStatement(sql);
ps.setObject(1,name);
ps.setObject(2,password);
ResultSet rs = ps.executeQuery();
while (rs.next()){
int id = rs.getInt("id");
String studentName = rs.getString("studentName");
String password1 = rs.getString("password");
LocalDate localDate = rs.getDate("birthday").toLocalDate();
LocalDateTime birthday = localDate.atStartOfDay();
int classID = rs.getInt("classID");
Student student=new Student(id,studentName,password1,birthday,classID);
System.out.println(student.toString());
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
4.JDBC中的对象
4.1 Connection
Connection 接口:代表数据库连接对象 创建语句对象Statement createStatement():创建一个 Statement 对象PreparedStatement prepareStatement(String sql):创建一个 PreparedStatement 对象PreparedStatement prepareStatement(String sql, int autoGeneratedKeys):创建一个 PreparedStatement 对象,并设置该对象是否能获取自动生成的主键 控制事务void setAutoCommit(boolean autoCommit):false 为关闭自动提交,开启事务(MySQL 默认打开自动提交) void commit():提交事务,并释放所持有的数据库锁 void rollback():回滚事务,并释放所持有的数据库锁
事务提交和回滚
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(40),
money FLOAT
);
INSERT INTO account(`name`,money) VALUES('A',1000);
INSERT INTO account(`name`,money) VALUES('B',1000);
INSERT INTO account(`name`,money) VALUES('C',1000);
@Test
public void test() {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url="jdbc:mysql://localhost:3306/student_study?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
Connection connection = null;
//1.加载驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//2.连接数据库,代表数据库
connection = DriverManager.getConnection(url, username, password);
//3.通知数据库开启事务,false 开启
connection.setAutoCommit(false);
String sql = "update account set money = money-100 where name = 'A'";
connection.prepareStatement(sql).executeUpdate();
//制造错误
//int i = 1/0;
String sql2 = "update account set money = money+100 where name = 'B'";
connection.prepareStatement(sql2).executeUpdate();
connection.commit();//以上两条SQL都执行成功了,就提交事务!
System.out.println("success");
} catch (Exception e) {
try {
//如果出现异常,就通知数据库回滚事务
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4.2 Statement
Statement 接口:用于执行静态 SQL 语句(将 SQL 语句发送到数据库) 执行语句int executeUpdate(String sql):执行DML语句时返回受影响的行数; int executeUpdate(String sql, int autoGeneratedKeys):执行给定的 DML 语句,并设置此 Statement 生成的自动生成键是否能用于获取 ResultSet executeQuery(String sql):执行DQL语句,并返回査询结果对应的 ResultSet 对象 批量更新void addBatch(String sql):将给定的SQL命令添加到此 Statement 对象的当前命令列表中 int[] executeBatch():执行一批命令void clearBatch():清空此 Statement 对象的当前 SQL 命令列表 获取自动生成主键ResultSet getGeneratedKeys():获取由于执行此 Statement 对象而创建的所有自动生成的主键
4.3 PreparedStatement
PreparedStatement 接口,Statement 的子接口,用于执行带占位符(?)参数的 SQL 语句 给参数设值即添加到批处理setXxx(int parameterIndex, Xxx value):根据索引(从 1 开始) 执行语句int executeUpdate():执行 DML 语句或 DDL 语句(无须接收 SQL 字符串)ResultSet executeQuery():执行 DQL 语句,不需接受sql参数。preparedStatement可以阻止简单sql注入
4.4 ResultSet
boolean next():将光标从当前行移动到下一行(光标的初始位置是第一行之前)Xxx getXxx(int columnIndex):获取当前行中的指定列索引(从 1 开始)的数据Xxx getXxx(String columnName):获取当前行中的指定列名的数据
5.properties文件
在实际开发中,我们一般情况下,会把配置相关的信息,放在 xx.properties 中保存。也方便修改
-
properties文件应放在resources包下。可以了解classpath
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/sql_study?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
user=root
password=123456
public class PropertiesJdbcTest {
public static void readLoading() throws IOException {
// 读取放在resources包下的properties文件
InputStream resourceAsStream = PropertiesJdbcTest.class.getClassLoader().getResourceAsStream("db.properties");
// Properties实例
Properties properties=new Properties();
// 加载properties文件
properties.load(resourceAsStream);
String driver=properties.getProperty("driver");
System.out.println(driver);
}
public static void main(String[] args) throws IOException {
readLoading();
}
}
6.JDCUtils工具类
<!-- Mysql数据库依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
JDBC工具类
/**
* @Author Mga
* @Date 2022/9/16 9:59
* @注释 JDBC数据库工具类
* 其中有两个方法需要注意querySql()、query
* 使用要求数据库字段要和pojo字段名一致,不然反射来实例对象有误
*/
public class JDBCUtils {
// 创建数据库连接对象
private Connection connection = null;
/**
* 利用构造方法给Connection赋值
*/
public JDBCUtils() {
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 数据库连接常量
String url = "jdbc:mysql://localhost:3306/sql_study?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8";
String username = "root";
String password = "123456";
connection = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
/**
* SQL查询
*
* @param sql
* @param t
* @param objects
* @param <T>
* @return
*/
public <T> List<T> querySql(String sql, T t, Object... objects) {
//声明jdbc变量
List<T> list = new ArrayList<>();
try {
// 创建预编译器
PreparedStatement ps = connection.prepareStatement(sql);
//给占位符赋值
if (objects != null) {
for (int i = 0; i < objects.length; i++) {
ps.setObject((i + 1), objects[i]);
}
}
// 执行预编译器
ResultSet resultSet = ps.executeQuery();
// 这下面就是利用反射来创建一个传来的参数T
// 获取结果集所有字段的信息
ResultSetMetaData metaData = resultSet.getMetaData();
// 获取字段数量
int columnCount = metaData.getColumnCount();
// 遍历resultSet
while (resultSet.next()) {
// 利用反射创建Class对象
Class<?> object = t.getClass();
// 实例化class对象
try {
T o = (T) object.newInstance();
for (int count = 1; count <= columnCount; count++) {
// 获取单个字段
String columnName = metaData.getColumnName(count);
// 获取字段对应的setter方法
String methodName = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
//获取字段java类型的完全限定名
String columnClassName = metaData.getColumnClassName(count);
// 创建方法对象
Method method = object.getDeclaredMethod(methodName, Class.forName(columnClassName));
//调用setter方法,执行对象属性赋值
method.invoke(o, resultSet.getObject(columnName));
}
list.add(o);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* SQL修改 SQL删除 SQL添加
*
* @param sql
* @param objects
* @return
*/
public boolean updateExecute(String sql, Object... objects) {
boolean flog = false;
try {
// 创建controlIndex来控制预编译器赋值
int controlIndex = 1;
PreparedStatement ps = connection.prepareStatement(sql);
// 该字段赋值
for (Object object : objects) {
ps.setObject(controlIndex++, object);
}
flog = ps.executeUpdate() > 0;
} catch (Exception e) {
e.printStackTrace();
}
return flog;
}
/**
* 查询类
*
* @param sql
* @return
*/
public ResultSet query(String sql, List<Object> params) {
try {
//准备好的报表/SQL
PreparedStatement preparedStatement = connection.prepareStatement(sql);
if (params != null) {
int index = 1;
for (Object param : params) {
preparedStatement.setObject(index++, param);
}
}
//执行准备好的报表/SQL
ResultSet resultSet = preparedStatement.executeQuery();
return resultSet;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}