jdbc是一个组件,能都被多种数据库访问,由java语言编写的类和接口组成
为什么要学习JDBC规范
JDBC是java连接数据库的一个标准,由数据库各个厂商来完成接口的实现
1.Class.forName(com.mysql.jdbc.Driver);
2.Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名称","root(用户名)","密码")
//如果是本机端口为3306,可以省略
Connection connection =DriverManager.getConnection("jdbc:mysql:///数据库名称","root(用户名)","密码")
// ? 使用的是占位符来进行拼接
3.String sql = "update t_student set name=? ,age=?,email=? where id=?"
//获取预编译对象,传入sql
4.PreparedStatement statement = connection.prepareStatement(sql);
//执行
statement.executeUpdate();
//释放资源
statement.close();
connection.close();
在使用PreparedStatement 调用executeUpdate()等操作时,最好不要传入sql语句
DAO(Data Acess Object ):数据访问对象 (面向对象的数据库接口),自己定义接口与实现实现类的设计思想,用于封装减少重复代码,DAO其实就是一个组件(可以重复使用)
使用倒置域名定义DAO包
dao包中接口的命名规范 IXxxDAO
impl包中的实现类命名规范 XXXDAOImpl
ResultSet接口 :通过执行DQL语句查询之后的结果对象
ResultSet对象具有指向其当前数据行的光标.next()方法将光标移动到下一行,移到下一行时(上一行的数据会被覆盖)如果Result对象没有下一行时返回false,所以可以使用while循环进行迭代
例子:
package cn.k.domain;
@Data
public class Student {
private Long id;
private String name;
private Integer age;
private String email;
}
public interface IStudentDAO {
//操作数据库的增删改查方法
//添加
void insert(Student student);
//删除
void deleteById(Long id);
//修改
void update(Student student);
//查询
Student selectById(Long id);
//查询所有
List<Student> selectAll();
}
public class StudentDAOImpl implements IStudentDAO {
@Override
public Student selectById(Long id) {
Student student = new Student();
String sql = "select*from t_student where id=?";
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接对象
connection = DriverManager.getConnection("jdbc:mysql:///product", "root", "123");
//获取预编译对象
statement = connection.prepareStatement(sql);
//设置参数
statement.setLong(1, id);
//发送 数据到数据库服务器
resultSet = statement.executeQuery();
//迭代结果集
while (resultSet.next()) {
long id1 = resultSet.getLong("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
String email = resultSet.getString("email");
student.setId(id1);
student.setName(name);
student.setAge(age);
student.setEmail(email);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭资源
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return student;
}
}
对代码进行优化,即重构,从代码量来讲更加简约,将相同构造的代码抽取出来,进行分类
代码的重构
1.对资源释放进行抽取; 2.对连接对象进行抽取 ; 3.对连接数据库的参数进行了抽取
4.对DML操作进行模板化实现,达到代码的复用性目的
5.对DQL操作进行模板化实现,达到代码的复用性目的
- 定义工具类Util包
package cn.kent.util;
import java.sql.*;
import java.util.Properties;
public final class JDBCUtil {
private JDBCUtil(){
}
private static Properties properties=new Properties();
//静态代码块
static {
try {
//加载配置文件
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
//加载驱动,只加载一次
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
//获取连接对象
Connection connection =null;
try {
connection= DriverManager.getConnection(
properties.getProperty("url"),
properties.getProperty("username"),
properties.getProperty("password")
);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//释放资源
public static void release(PreparedStatement statement, Connection connection, ResultSet resultSet){
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//释放资源,重载关闭两个资源
public static void release(PreparedStatement statement, Connection connection){
release(statement,connection,null);
}
}
public abstract class DQLUtil {
//编写DML方法,传入SQL语句,与可变参数
public static void executeUpdate(String sql,Object...objects){
Connection connection=null;
PreparedStatement statement=null;
try {
//获取连接对象,调用JDBCUtil中的getConnection()获取到连接对象
connection=JDBCUtil.getConnection();
//获取语句对象
statement=connection.prepareStatement(sql);
//设置参数
for (int i = 0; i < objects.length; i++) {
statement.setObject(i+1,objects[i]);
}
//执行sql的DML方法
statement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放资源
JDBCUtil.release(statement,connection);
}
}
//查询方法 ,定义泛型 ,提供字节码 ,自定义接口ResultSeHandler
public static <T> List<T> executeQuery(String sql, ResultSeHandler handler,Class<T> als, Object...objects) {
List<T> list =new ArrayList<>();
Connection connection=null;
PreparedStatement statement=null;
ResultSet resultSet=null;
try {
//获取连接对象
connection=JDBCUtil.getConnection();
//获取语句对象
statement=connection.prepareStatement(sql);
//设置参数
for (int i = 0; i < objects.length; i++) {
statement.setObject(i+1,objects[i]);
}
//执行sql
resultSet =statement.executeQuery();
//需要进行返回值,调用接口实现中的方法
List list1 = handler.handleResultSet(resultSet, als);
return list1;
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.release(statement,connection,resultSet);
}
return list;
}
}
public interface ResultSeHandler<T> {
List<T> handleResultSet(ResultSet resultSet,Class<T> acl);
}
public class ResultSetHandlerImpl<T> implements ResultSeHandler<T> {
@Override
public List<T> handleResultSet(ResultSet resultSet, Class<T> acl) {
List<T> list =new ArrayList<>();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(acl, Object.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
while (resultSet.next()) {
T t =acl.newInstance();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//获取对象中的属性
String name = propertyDescriptor.getName();
//获取数据库中的列名
Object value = resultSet.getObject(name);
// System.out.println(value);
//获取set方法
Method writeMethod = propertyDescriptor.getWriteMethod();
//执行
writeMethod.invoke(t,value);
}
//装进集合
list.add(t);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
- domain包
@Data
public class Teacher {
private int id;
private String name;
private Integer age;
private String email;
}
- dao包
定义接口ITeacherDAO
public interface ITeacherDAO {
//添加
void insert(Teacher teacher);
//删除
void delete(int id);
//改
void update(Teacher teacher);
//查询指定id
Teacher select(int id);
//查询所有
List<Teacher> selectAll();
}
public class TeacherDAOImpl implements ITeacherDAO {
//插入
@Override
public void insert(Teacher teacher) {
String sql = "insert into t_teacher (name,age,email) values(?,?,?)";
DQLUtil.executeUpdate(sql,teacher.getName(),teacher.getAge(),teacher.getEmail());
}
//删除
@Override
public void delete(int id) {
String sql ="delete from t_teacher where id =?";
DQLUtil.executeUpdate(sql,id);
}
//更新
@Override
public void update(Teacher teacher) {
String sql ="update t_teacher set name=?,age=?,email=? where id=?";
DQLUtil.executeUpdate(sql,teacher.getName(),teacher.getAge(),teacher.getEmail(),teacher.getId());
}
//查询 DQL
@Override
public Teacher select(int id) {
String sql = "select * from t_teacher where id=?";
List<Teacher> list = DQLUtil.executeQuery(sql, new ResultSetHandlerImpl(), Teacher.class, id);
if (list!=null &&list.size() >0){
return list.get(0);
}
return null;
}
//查询整个集合
@Override
public List<Teacher> selectAll() {
String sql = "select*from t_teacher";
List<Teacher> list1 = DQLUtil.executeQuery(sql, new ResultSetHandlerImpl(), Teacher.class);
return list1;
}
}
- test包
public class TeacherDAOImplTest {
private static ITeacherDAO teacherDAO =new TeacherDAOImpl();
//插入
@Test
public void insert() {
Teacher teacher = new Teacher();
teacher.setName("月月");
teacher.setAge(12);
teacher.setEmail("我爱小轩");
teacherDAO.insert(teacher);
}
//删除
@Test
public void delete() {
teacherDAO.delete(5);
}
//更新
@Test
public void update() {
Teacher teacher =new Teacher();
teacher.setName("臭猪");
teacher.setAge(18);
teacher.setEmail("fewgw");
teacher.setId(6);
teacherDAO.update(teacher);
}
//查询指定id
@Test
public void select() {
Teacher select = teacherDAO.select(1);
System.out.println(select);
}
//查询集合
@Test
public void selectAll() {
List<Teacher> list = teacherDAO.selectAll();
System.out.println(list);
}
}
事务(Transaction ,简称tx)
让多个操作,捆绑在一起,多个操作中有一个失败,那么整个操作失败
在数据库中,事务是指一组逻辑操作单元,使数据从一种状态换成另外一种状态,保证了操作要么同时成功,要么同时失败
javax.sql.DataSource 接口
用来存放多个连接对象,避免了资源浪费
基本四要素:driverClassName,url,username,password
其他属性:对连接对象被限制的配置
常见的DataSource实现
DBCP与druid步骤基本一致
首先导入相关数据池的jar包
//DBCP数据库连接池 ,改造前
public class DBCPDemo {
public static void main(String[] args) throws SQLException {
DataSource dataSource=setupDataSource();
Connection connection=dataSource.getConnection();
System.out.println("connection = " + connection);
}
public static DataSource setupDataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUsername("root");
ds.setPassword("123");
ds.setUrl("jdbc:mysql:///product");
return ds;
}
}
但是这样去使用连接池,上述代码就会产生了硬编码,我们应该对其进行优化,即主流写法
首先使用DBCP连接池时,对应的数据库信息应该从properties配置文件中读取,使用连接池首先需要创建DataSource对象,其中DBCP已经提供创建该对象的工厂方法BasicDataSourceFactory.createDataSource(Properties properties)
,并且可以传入properties对象并读取该配置文件的内容,那么步骤就简化很多了
//注意名字是有指定写法的,不能随意修改
driverClassName=com.mysql.jdbc.Driver
username=root
password=123
url=jdbc:mysql:///product
public final class DBCPUtil {
private DBCPUtil() {
}
private static DataSource ds = null;
//使用静态代码块,加载配置文件资源
static {
try {
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
//加载进properties内存中
properties.load(inputStream);
//创建datasource对象,并传入properties对象
ds = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//写一个工具方法 ,直接调用
public static DataSource getDataSource() {
return ds;
}
//为了更简便 ,直接把连接对象步骤写进该方法
public static Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
public static void main(String[] args) throws SQLException {
//直接使用工具类,调用即可,成功连接到数据库
Connection connection =DBCPUtil.getConnection();
System.out.println("connection = " + connection);
}