JDBC:Java访问数据库的技术
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API。
DAO Database Access Object(数据库访问对象) 在工程中,从属于dao层。 respository(仓库)
之前处理其他业务逻辑,与DB无关,成为service层,比如处理注册登录的业务功能。
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API。
DAO Database Access Object(数据库访问对象) 在工程中,从属于dao层。 respository(仓库)
之前处理其他业务逻辑,与DB无关,成为service层,比如处理注册登录的业务功能。
一、向Eclipse工程中导入jar包(一般的封装类在项目中都放在一个单独的page包中util)
创建包的时候一般是需要后缀为dao。如:com.zhiyou.dao
1.首先需要导入一个jar包(第三方工具包):mysql-connector-java-8.0.17.jar
(1)在网上下载:Connector/J中
(2)在MySQL的安装包中找到:
MySQL5.8版本之后的MySQL在安装过程中也会把这个jar包下载下来。
位置在:C:\Program Files (x86)\MySQL\Connector J 8.0.17.jar
2.将jar包加入到工程中:目的是可以使用jar中的工具类,能让eclipse编译时可以识别
(1)右键工程名字创建lib(资源库)文件夹(Floder)
(2)将jar包拖拽到lib文件夹中,选择copy file
(3)右键lib中的jar包,选择Build Path --->Add to Build Path
(4)Add to Build Path之后会在lib文件夹上方出现Referenced Librarice(被使用的资源库),里面包含这个jar包(jar包的图标会变)
这个jar包里面放的都是工具包和工具类的编译类(xx.class)。关键:com.mysql.cj.jdbc.Driver.class
二、JDBC步骤分析
步骤:
1.加载驱动
2.建立连接
3.准备SQL
4.执行SQL
5.处理结果
6.断开连接
(1)实现查询功能(Query)
1 加载驱动
加载jar包中的驱动类Driver.class,用到的方式是反射
使用Class.forName 这一反射方式加载Driver类的原因是因为 :倘若使用new Driver()方式,则会首先执行Driver类中的静态代
码块, 而静态代码块中又出现了一次new Driver(),如此 相当于new了两次Driver对象,不好!
所以,使用Class.forName也会执行Driver类中的静态代码块,最终也就只执行了一次new对象。这种方式才是我们想要的。
String----》find class ---》load---》static---》new Driver()
1.Class.forName("com.mysql.cj.jdbc.Driver"); :使用Class类的forName方法来加载驱动
需要解决异常(throws抛出或者try/catch解决)
2.建立连接 : 使用DriverManager类的connection方法返回一个Connection的实例
(1)使用DriverManager中的getConnection(url,user,password)方法,返回值类型是Connection类型
DriverManager.getConnection(url,username,password);
给url赋值为:"jdbc:mysql://localhost:3306/student?serverTimezone=GMT%2B8",用户名及密码为安装数据库时设置的。
都是String类型
url的格式:协议//本机主机:端口号/数据库名?serverTimezone=GMT%2B8
url的格式中数据库后面的是mysql8版本必须指定的时区,需要在数据库后面加上配置信息(否则会出现时区异常)
String url = "jdbc:mysql://localhost:3306/student?serverTimezone=GMT%2B8";
String user = "root";
String password = "1234";
(2)因为在准备下一步的准备SQL中要使用DriverManage.getConnection(url,user,password)方法拿到的Connection对象
connection中的方法,所以需要创建对象并将方法返回值赋给Connection的对象connection
Connection connection = null;
2. connection = DriverManager.getConnection(url,user,password);
(3)解决异常(throws抛出或者try/catch解决)
3.准备SQL : 使用Connection中的prepareStatement方法,返回了一个PrepareStatement实例。将sql语句给数据库先编译
(1)使用connection中的prepareStatement()方法,参数为数据库语言,如:sql,返回值类型为PreparedStatement对象
connection.perpareStatement(sql);
(2)因为在下一步的执行SQL中要使用PreparedStatement对象的方法,所以需要创建一个PreparedStatement对象,并将
方法中的返回值赋予对象
PreparedStatement pStatement = null;
3. pStatement = connection.prepareStatement(sql);
对于方法中的参数sql就是sql语句。属于字符串String类型。需要定义sql操作语句
String sql = "select * from student";
(3)解决异常(throws抛出或者try/catch解决)
4.执行SQL(查询为例 ) :使用PrepareStatement中的executeQuery方法,返回一个ResultSet实例
查询是用executeQuery()方法 增加删除修改都是用excuteUpdate()方法)使用Update时不需要第五步且第四步不同
(1)使用PreparedStatement对象pStatement的executeQuery()方法,返回值类型为ResultSet
pStatement.executeQuery();
(2)因为在下一步的处理结果中需要使用ResultSet对象来拿值,所以需要创建ResultSet对象并将方法中的返回值赋予对象
Result rSet = null;
4. rSet = pStatement.executeQuery();
5.处理结果
拿值并打印 使用getXxx拿值,类型由表中字段类型决定,其中参数选择int就使用列的索引值,选择String就使用列的字段名
while(rSet.next()){
int id = rSet.getInt(1); 第一种方法:列的索引值 默认是从1开始
String name = rSet.getString("name"); 第二种方法:列的字段名
int age = rSet.getInt("age");
System.out.println("从数据库中student表中取得的值为: " + id + "," + name + "," + age);
}
6.断开连接
释放资源
从最下层的对象开始关闭,即先创建的最后关闭,最后创建的优先关闭
(1)rSet.close() pStatemen.close(); connection.close();
(2)解决异常
(2)实现增删改功能(Update)
前面三步与查询一样
(第四步)1.添加固定值:
对于修改的返回结果是成功修改了几条记录,所以返回值为int
int record = pStatemen.executeUpdate();
因为修改记录不需要返回结果,所以省略第五步,且不会创建ResuleSet对象
2.调用方法添加不定值:
public static void main(String[] arg){
upDate(5,'zhangsan',20);
}
这些JDBC语句写在main方法之外的静态方法中
public static void upDate(int i,String string,int age){
String sql = "insert into user values(?,?,?)"; ?是占位符
PreparedStatement pStatement = connection.prepareStatement(sql);
//下面的这些set方法中的参数,第一个是索引值(默认从1开始),第二个是传进来的参数名。(与方法的参数一一对应)
// pStatement.setInt(1, i);
pStatement.setObject(1, i);
// pStatement.setString(2, string);
pStatement.setObject(2, string);
pStatement.setObject(3, j);
int record = pStatemen.executeUpdate();
(5)关闭连接
pStatement.close(); connection.close();
三、编写JDBC代码
1.使用 try/catch解决异常 实现查询数据库功能的代码
public static void main(String[] args) {
//1.加载驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("加载驱动成功");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("加载驱动失败");
}
//2.输入用户名密码建立连接
String url = "jdbc:mysql://localhost:3306/student?serverTimezone=GMT%2B8";
String user = "root";
String password = "1234";
Connection connection = null;
try {
connection = DriverManager.getConnection(url, user, password);
System.out.println("建立连接成功");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("建立连接失败");
}
//3.准备输入查询或者修改sql
String sql = "select * from student";
PreparedStatement pStatement = null;
try {
pStatement = connection.prepareStatement(sql);
System.out.println("准备的sql语句正确");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("准备的sql语句错误");
}
//4.执行sql的查询或者修改语句
ResultSet rSet = null;
try {
rSet = pStatement.executeQuery();
System.out.println("查询成功");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("查询失败");
}
//5.处理结果(打印)
try {
while(rSet.next()) {
int id = rSet.getInt(1);
String name = rSet.getString("name");
int age = rSet.getInt("age");
System.out.println("id为" + id + " 的学生叫做:" + name + " 今年" + age + "岁");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//6.关闭连接,释放资源
//rSet
try {
rSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//pStatement
try {
pStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//connection
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
输出结果:
加载驱动成功
建立连接成功
准备的sql语句正确
查询成功
id为1 的学生叫做:张三 今年18岁
2.使用throws解决异常 实现向数据库添加固定值的功能的代码
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.建立连接
String url = "jdbc:mysql://localhost:3306/student?serverTimezone=GMT%2B8";
String user = "root";
String password = "1234";
Connection connection = null;
connection = DriverManager.getConnection(url, user, password);
//3.准备插入SQL
String sql = "insert into student values(4,'麻子',21) ";
PreparedStatement pStatement = null;
pStatement = connection.prepareStatement(sql);
//4.执行SQL
int roeForExecution = pStatement.executeUpdate();
System.out.println("插入操作执行成功");
//5.关闭连接
pStatement.close();
connection.close();
}
输出结果:插入操作执行成功
3.使用throws解决异常 向数据库添加不固定数值
public class JDBCTestThree {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
upDate(5, "老张", 23);
}
public static void upDate(int i ,String j,int k) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/student?serverTimezone=GMT&2B8";
String user = "root";
String password = "1234";
Connection connection = DriverManager.getConnection(url, user, password);
String sql = "insert into student values(?,?,?)";
PreparedStatement pStatement = connection.prepareStatement(sql);
// pStatement.setObject(1, i); 使用Object类型传参数
pStatement.setInt(1, i);
// pStatement.setString(2, j); 使用参数类型传参数
pStatement.setObject(2, j);
// pStatement.setObject(3, k);
pStatement.setInt(3, k);
int record = pStatement.executeUpdate();
System.out.println("成功添加");
pStatement.close();
connection.close();
}
}
输出结果:成功添加
四、封装JDBC
1.封装的JDBC
public class DButil {
//在工具类中,如果有一个以上的方法使用相同的变量,就把这个变量定义为属性
private static Connection connection;
private static PreparedStatement preparedStatement;
private static ResultSet resultSet;
//设计规则:死值都设为常量,这样在以后改变的时候在属性上面修改就可以
private static final String URL_STRING = "jdbc:mysql://localhost:3306/student?serverTimezone=GMT%2B8";
private static final String USER_STRING = "root";
private static final String PASS_STRING = "1234";
//1.加载驱动只需要执行一次即可。所以定义在静态代码块中
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static ResultSet query(String sql,Object[] objects) {
connection = getConnection();
try {
preparedStatement = connection.prepareStatement(sql);
for(int i = 0;i < objects.length;i++) {
//用于给sql语句的占位符赋值(参数?的绑定)sql语句中的?索引是从1开始的
preparedStatement.setObject(i+1, objects[i]);
}
resultSet = preparedStatement.executeQuery();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//因为查询时候的表都不同,所以不能在此方法中处理结果集。要写在main方法中,需要修改查询结果格式的时候就在main方法中修改
//所以此方法只需要返回resultSet即可
return resultSet;
}
public static void update(String sql2, Object[] objects2) {
int row;
connection = getConnection();
try {
preparedStatement = connection.prepareStatement(sql2);
//参数?的绑定(sql语句中的?索引是从1开始的)
for(int i = 0;i < objects2.length;i++) {
preparedStatement.setObject(i+1, objects2[i]);
}
row = preparedStatement.executeUpdate();
System.out.println("row:" + row);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static Connection getConnection() {
try {
connection = DriverManager.getConnection(URL_STRING, USER_STRING, PASS_STRING);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return connection;
}
//关闭,释放资源:先创建后关闭,后创建的先关闭:先进后出
public static void close() {
if(resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
注意:在executeUpdate()和executeQuery()方法之前,通过for循环中的prepareStatement.setObject(i+1,i)方法来完成参数绑定,sql语句中的?索引是从1开始的
2.不使用model类的测试类
public class Test {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
testQuery();
testUpdate();
}
//添加
private static void testUpdate() {
// TODO Auto-generated method stub
String sql2 = "insert into student values(?,?,?,?)";
Object[] objects2 = {5,"小明",20,2};
DButil.update(sql2,objects2);
DButil.close();
}
//查询
private static void testQuery() throws SQLException {
String sql = "select * from student where s_id=?";
//创建数组,在DButil中使用数组中的值为sql中的?占位符进行绑定
Object[] objects = {2};
ResultSet resultSet = DButil.query(sql,objects);
while(resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
int age = resultSet.getInt(3);
System.out.println(id + name + age);
DButil.close();
}
}
}
输出结果:
2李四21
row:1
3.使用model类的测试类(查询全部的学生信息):
按照封装的思想,一般为了java代码使用,所以从db的表中获得的一条记录,会转换成一个model类的对象。
如果是多条记录,会转换成多个对象,并且存放在集合中。
注意:使用User类来创建对象的时候,要导包
public class Test {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
testQuery();
testUpdate();
}
//查询
private static void testQuery() throws SQLException {
String sql = "select * from student ";
//创建数组,在DButil中使用数组中的值为sql中的?占位符进行绑定
Object[] objects = {};
ResultSet resultSet = DButil.query(sql,objects);
while(resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
int age = resultSet.getInt(3);
int c_id = resultSet.getInt(4);
System.out.println(id + name + age + c_id);
User user = new User(id, name, age, c_id);
System.out.println(user);
List list = new ArrayList();
list.add(user);
System.out.println(list);
System.out.println();
}
DButil.close();
}
//添加
private static void testUpdate() {
// TODO Auto-generated method stub
String sql2 = "insert into student values(?,?,?,?)";
Object[] objects2 = {5,"小明",20,2};
DButil.update(sql2,objects2);
DButil.close();
}
}
输出结果:
id:1 name:张三 age:30 c_id:1
User [id=1, name=张三, age=30, c_id=1]
[User [id=1, name=张三, age=30, c_id=1]]
id:2 name:李四 age:21 c_id:2
User [id=2, name=李四, age=21, c_id=2]
[User [id=2, name=李四, age=21, c_id=2]]
id:3 name:王五 age:23 c_id:1
User [id=3, name=王五, age=23, c_id=1]
[User [id=3, name=王五, age=23, c_id=1]]
id:4 name:麻子 age:20 c_id:3
User [id=4, name=麻子, age=20, c_id=3]
[User [id=4, name=麻子, age=20, c_id=3]]