文章目录
一、JDBC基本概念
(1)JDBC:
1.概念:
Java DataBase Connectivity Java数据库连接,Java语言操作数据库
- JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,
即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。
我们可以使用这套接口(J0BC)编程,真正执行的代码是驱动jar包中的实现类
2.快速入门:
-
步骤:
- 导入驱动jar包
- 注册驱动
- 获取数据库连接对象 connection
- 定义sql
- 获取执行sq1语句的对象 Statement
- 执行sq1,接受返回结果
- 处理结果
- 释放资源
-
代码实现:
public class JdbcDemo02 {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
//1.导入jar包(之前已经导入过就无需再进行导入操作)
try {
//2.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//3.获取Connection连接对象
conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "xxzjwnx");
//4.写入sql语句
String sql = "insert into account values (3,'wangwu',3000)";
//5.获取sql执行的对象Statement
stat = conn.createStatement();
//6.执行sql语句
int result = stat.executeUpdate(sql); //处理结果后影响的行数
System.out.println(result);
if(result>0){
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
3.详解各个对象
①DriverManager:驱动管理对象
- 功能:
-
注册驱动:告诉程序该使用哪一个数据库驱动jar
static void registerpriver(Driver driver):注册与给定的驱动程序 DriverManager。
写代码使用:class.forName(“com.mysq1.jdbc.Driver”);
通过查看源码发现:在com.mysq1.jdbc.Driver类中存在静态代码块static { try { java.sql.DriverManager.registerpriver(new Driver()); }catch(SQLException E){ throw new RuntimeException("can't register driver!"); } }
注意:mysq15之后的驱动jar包可以省略注册驱动的步骤。
-
获取数据库连接
- 方法:static Connection getConnection(String url,String user,string password)
- 参数:
- ur1:指定连接的路径
- 语法:jdbc:mysq1://ip地址(域名):端口号/数据库名称
- 例子:jdbc:mysql://localhost:3306/db3
- 细节:如果连接的是本机mysq1服务器,并目mysql服务默认端口是3306,
则ur1可以简写为:jdbc:mysq1:///数据库名称
- ur1:指定连接的路径
- user:用户名
- password:密码
-
②Connection:数据库连接对象
- 功能:
- 获取执行sq1的对象
- Statement createstatement()
- Preparedstatement preparestatement(string sql)
- 获取执行sq1的对象
- 管理事务:
- 开后事务:setAutocommit(boolean autocommit):调用该方法设置参数为false,即开启事务
- 提交事务:commit()
- 回滚事务:rollback()
③Statement:执行sql的对象
- 执行sql
- boolean execute(string sql):可以执行任意的sq1了解
- int executeUpdate(string sql):执行DML(insert、update、delete)语句、
DDL(create,alter、drop)语句
*返回值:影响的行数,可以通过这个影响的行数判断DML语句
是否执行成功返回值>0的则执行成功,反之,则失败。 - Resultset executeQuery(string sql):执行DQL(select)语句
- 练习:
- account表添加一条记剥
- account表修改记录
- account表删除一条记录
- 代码实现:(实现其中的一个,其余的道理相同)
//account表中修改记录
public class JdbcDemo03 {
public static void main(String[] args) {
Connection conn = null;
Statement stat =null;
try {
//1.驱动注册
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象
conn = DriverManager.getConnection("jdbc:mysql:///db2", "root", "xxzjwnx");
//3.定义sql语句
String sql = "update account set balance = 1000 where id = 1";
//4.获取执行sql对象Statement
stat = conn.createStatement();
//5.执行sql语句
int result = stat.executeUpdate(sql); //返回sql语句中影响最终结果的行数
System.out.println(result);
if(result>0){
System.out.println("修改成功");
}else {
System.out.println("添加失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
④Resultset:结果集对象,封装查询结果
- boolean next():游标向下移动一行,判断当前行是否是最后一行未尾(是否有数据),
如果是,则返回false,如果不是则返回true - getxxx(参数):获取数据
- xxx:代表数据类型如:int getInt(),string getstring()
- 参数:
- int:代表列的编号,从1开始如:getstring(1)
- string:代表列名称。如:getDouble(“balance”)
注意:
- 使用步骤:
- 游标向下移动一行
- 判断是否有数据
- 获取数据
//循环判断是否是最后一行
while(rs.next()){
int id = rs.getInt(1);
String name = rs.getString(“name”);
double balance = rs.getDouble(“balance”);
System.out.println(id+"----"+name+"----"+balance);
}
- 练习
- 定义一个方法,查询emp表的数据捋其封装为对象,然后装载集合,返回。
- 定义Emp类
- 定义方法public ListfindAll(){}
- 实现方法select*from emp;
- 定义一个方法,查询emp表的数据捋其封装为对象,然后装载集合,返回。
⑤Preparedstatement:执行sql的对象
- SQL注入问题:在拼接sql时,有一些sq1的特殊关键字参与字符串的拼接。会造成安全性问题
- 输入用户随便,输入密码:a’or’a’='a
- sql:select * from user where username = ‘fhdsjkf’ and password = ‘a’ or ‘a’ = ‘a’
- 解决sq1注入问题:使用Preparedstatement对象来解决
- 预编译的SQL:参数使用?作为占位符
- 步骤:
- 导入驱动jar包mysql-connector-java-5.1.37-bin.jar
- 注册驱动
- 获取数据库连接对象 Connection
- 定义sql
- 注意:sql的参数使用?作为占位符。
如:select*from user where username=?and password=?;
- 注意:sql的参数使用?作为占位符。
- 获取执行sq1语句的对象 Preparedstatement Connection.preparestatement(string sql)
- 给?赋值:
- 方法:setxxx(参数1,参数2)
- 参数1:?的位置编号从1开始
- 参数2:?的值
- 方法:setxxx(参数1,参数2)
- 执行sql,接受返回结果,不需要传递sql语句
- 处理结果
- 释放资源
- 注意:后期都会使用Preparedstatement
来完成增删改查的所有操作
1. 可以防止SQL注入
2. 效率更高
二、抽取JDBC工具类:JDBcUtils(配置文件)
- 目的:简化书写
- 分析:
- 注册驱动也抽取
- 抽取一个方法获取连接对象
- 需求:不想传递参数(麻烦),还得保证工具类的通用性。
- 解决:配置文件
jdbc.properties url=
user=
password=
- 抽取一个方法释放资源
- 代码实现
//这是新建文件jdbc.properties的代码
url=jdbc:mysql:///db2
user=root
password=xxzjwnx
driver=com.mysql.jdbc.Driver
//工具类代码的实现
public class JdbcUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
/*
文件的读取,只需要读取一次即可拿到这些值,使用静态代码块
*/
static {
try {
//读取资源文件,获取值
//1.创建Properties集合类
Properties pro = new Properties();
//获取src路径下的文件的方式---->ClassLoader类加载器
ClassLoader classLoader = JdbcUtils.class.getClassLoader();
URL resource = classLoader.getResource("jdbc.properties");
String path = resource.getPath();
//2.进行加载文件
//pro.load(new FileReader("E:\\IDE_WorkPlace\\jdbc_learn\\01_jdbc\\src\\jdbc.properties"));
pro.load(new FileReader(path));
//3.获取值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/*
* 获取连接的方法
* return 连接对象
* */
public static Connection getConnection2() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
//对释放资源的方法(抛出异常的方法)进行简化
public static void close(ResultSet rs, Statement stat, Connection conn){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- 练习:需求:
- 通过键盘录入用户名和密码
- 判断用户是否登录成功
select* from user where username =" " and password = " " ;
*如果这个sq1有查询结果,则成功,反之,则失败
//2.写入sql
String sql = “select * from user where username = '”+username+"’ and password = ‘"+password+"’ ";
//判断是否登录成功
//2.调用方法
boolean b = new JdbcDemo08Load_Practise().login(username, password);
//3.判断结果输出不同语句
if(b){
System.out.println(“登录成功”);
}else{
System.out.println(“你所输入的用户名密码错误!”);
}
步骤1 :创建数据库表user
CREATE TABLE USER (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32),
passsword VARCHAR(32)
);
INSERT INTO USER VALUES (NULL,‘zhangsan’,‘123’);
INSERT INTO USER VALUES (NULL,‘lisi’,‘234’);
三、JDBC控制事务:
- 事务:一个包含多个步骤的业务操作。
如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。 - 操作:
- 开后事务
- 提交事务
- 回滚事务
3 .使用connection对象来管理事务
- 开后事务:setAutocommit(boolean autocommit):
调用该方法设置参数为false,即开后事务 - 提交事务:commit()
- 回滚事务:rollback()
四、数据库连接池
- 概念:其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,
当用户来访问数据库时,从容器中获取连接对象,
用户访问完之后,会将连接对象归还给容器。 - 好处:
- 节约资源
- 用户访问高效
- 实现:
- 标准接口:Datasource javax.sq1包下的
- 方法:
- 获取连接:getconnection()
- 归还连接:Connection.close()。
如果连接对象Connection是从连接池中获取的,
那么调用connection.close()方法,
则不会再关闭连接了。而是归还连接
- 方法:
- 一般我们不去实现它,有数据库厂商来实现
- C3p0:数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供的
- 标准接口:Datasource javax.sq1包下的
(1).C3P0:数据库连接池技术
- 步骤:
- 导入jar包(两个)c3p0-0.9.5.2.jar mchange-commons-java-e.2.12.jar,
- 不要忘记导入数据库驱动jar包
- 定义配文件:
- 名称:c3p0.properties或者c3p0-config.xml
- 路径:接捋文件放在src目录下即可。
- 加载配置文件。Properties
- 创建核心对象数据库连接池对象ComboPooledDatasource
- 获取连接:getconnection
- 导入jar包(两个)c3p0-0.9.5.2.jar mchange-commons-java-e.2.12.jar,
(2).Druid:数据库连接池实现技术,由阿里巴巴提供的(目前最常用)
- 步骤:
- 导入jar包druid-1.0.9.jar
- 定义配置文件:
- 是properties形式的
- 可以叫任意名称,可以放在任意目录下
- 加载配置文件。Properties
- 取数据库连接池对象:
通过工厂来来获取 DruidpatasourceFactory - 获取连接:getconnection
- 定义工具类
- 定义一个类JDBCUtils
- 提供静态代码块加载配置文件,初始化连接池对象
- 提供方法
- 获取连接方法:通过数据库连接池获取连接
- 释放资源
- 获取连接池的方法
- 工具类代码块的实现
public class JdbcUtils {
//定义初始化变量
private static DataSource ds;
//定义一个静态模块
static {
try {
//加载配置文件
Properties pro = new Properties();
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection2() throws SQLException {
return ds.getConnection();
}
//定义一个关闭流的方法
public static void closePool(Statement stat,Connection conn){
closePool(null,stat,conn);
}
public static void closePool(ResultSet rs, Statement stst, Connection conn){
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stst != null) {
try {
stst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) { //归还连接
e.printStackTrace();
}
}
}
//获取连接方法
public static DataSource getDataSource() {
return ds;
}
}
五、Spring JDBC(Template的使用)
- Spring框架对JDBC的简单封装。
提供了一个JDBCTemplate对象简化JDBC的开发 - 步骤:
- 导入jar包
- 创建]dbcTemplate对象。依赖于数据源Datasource
JdbcTemplate template=new JdbcTemplate(ds); - 调用dbcTemplate的方法来完成CRUD的操作
- update():执行DML语句。增、删、改语句
- queryForMap():查询结果捋结果集封装为map集合
- 注意:这个方法查询的结果集长度只能是1
- queryForList():查询结果捋结果集封装为list集合
- 注意:捋每一条记录封装为一个Map集合,
再将Map集合装载到List集合中
- 注意:捋每一条记录封装为一个Map集合,
- query():查询结果,捋结果封装为JavaBean对象
- query的参数:RowMapper
- 一般我们使用BeanPropertyRowMapper实现类。
可以完成数据到JavaBean的自动封装 - new BeanPropertyRowMapper<类型>(类型.class)
- 一般我们使用BeanPropertyRowMapper实现类。
- query的参数:RowMapper
- queryForobject:查询结果,捋结果封装为对象
- 一般用于聚合函数的查询
- 练习:*需求:
- 修改1号数据的salary为100002.添加一条记录
- 删除刚才添加的记录
- 查询id为1的记录,将其封装为Map集合
- 查询所有记录,捋其封装为List
- 查询所有记录,捋其封装为Emp对象的List集合
- 查询总记录数
- 有关练习部分(Template的使用)的代码块的实现
public class JdbcTemplateDemo02 {
/*
使用Test注解的方法进行书写,可以在一个类中不使用主方法的情况下独立执行并测试
*/
//添加一条记录
@Test
public void test1(){
JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "insert into account values (null,?,?)";
template.update(sql,"tianqi",1500);
}
//删除刚刚添加的记录
@Test
public void test2(){
JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
template.update("delete from account where balance = 1500");
}
//查询id为3的记录,将其封装位Map
//注意查询的结果集长度只能为1,将列名作为key,将行表作为value
@Test
public void test3() {
JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "select * from account where id = 1";
Map<String, Object> map = template.queryForMap(sql);
System.out.println(map); //{id=1, Name=zhangsan, balance=500}
}
//查询表中的所有记录
@Test
public void test4() {
JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "select * from account";
List<Map<String, Object>> list = template.queryForList(sql);
System.out.println(list);
}
//使用template中的query()方法来进行查询表中的所有记录
@Test
public void test5() {
JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "select * from account";
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
for (Emp emp : list) {
System.out.println(emp);
}
}
}