必要声明:参考B站up主 写给李华的信 (传智播客)
代码部分没有打上try catch 和 throw 的异常处理
Jdbc概念+快速入门
1、概念:官方Sun公司定义的一套操作所有关系型数据库的规则,即接口。各厂商去实现这套接口,即提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
2、快速入门
//1、导入驱动jar包
//2、注册驱动
Class.forName("com.mysql.jdbc.Driver"); //【要理解】
//3、捕获数据库连接对象
Connection conn = DriverManager.getConnection(url"jdbc:mysql://localhost:3306/db3",user"root",password"mysql_native password");
//4、定义sql语句
String sql = "update account balance = 500 where id = 1";
//5、获取执行sql的对象Statement
Statement stmt = conn.createStatement();
//6、执行sql语句
int count = stmt.executeUpdate(sql);
//7、处理结果
System.out.println(count);
//8、释放资源
stmt.close();
conn.close();
代码理解要点:注册驱动–加载进内存
注意:若涉及try catch时抽取变量:Connection conn = null; Statement stmt = null
各类详解
DriverManager
1、注册驱动:告诉程序该使用哪个数据库驱动jar包
static void registerDriver(Driver driver);
写代码使用:Class.forName(“com.mysql.jdbc.Driver”); //存在静态代码块含registerDriver(new Driver)
2、获得数据库连接
static Connection getConnection(String url, String user, String password);
Connection
1、获取执行sql的对象
Statement createStatement();
PreparedStatement preparedStatement(String sql);
2、管理事务
Statement
执行sql:
int executeUpdate(String sql); //执行DML(insert delete uppdate) DDL(create alter drop)
ResultSet executeQuery(String sql); //执行DQL(select) 结果集
ResultSet:结果集对象,封装查询结果
1、next();
boolean next() : 游标下移一行,如果此行有数据,true ; 无数据,false
getXxx(参数) 如: int getInt( ) , String getString()
参数:1、int:getString(1);
2、string : getdouble(“age”);
//1.注册驱动
//2.获取连接对象
//3.定义sql
String sql = "select *from account";
//4.获取执行sql对象
//5.执行sql语句
rs = stmt.executeQuery(sql); //已经抽取到外面
//6.处理结果
//6.1让游标下移一行
rs.next();
//6.2获取数据
int id = rs.getInt(1);
Sting name = rs.getSting("name");
System.out.println(id + "---"+ name );
//7.释放资源
2、处理结果的改进----遍历
while(rs.next())
{
获取数据
}
3、定义方法:查询emp表的数据,将其封装为对象,然后装载集合,返回
表->类 / 每一行的数据->一个对象(用)
*定义Emp类
*定义方法public List findAll(){}
*实现方法 select *from Emp
//主
public class JdbcDemo1{
public static void main(String[] args){
List<Emp> list = new JdbcDemo1.findAll();
System.out.println(list);
System.out.println(list.size());
}
}
public List<Emp> findAll(){
//抽取部分
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//1.注册
//2.获取连接对象
//3.定义sql
//4.获取执行sql对象
//5.执行sql
//6.遍历结果集,封装对象,装载集合
Emp emp = null; //【理解】
List<Emp> list = new ArrayList<Emp>(); //抽取到外面
while(rs.next()){
//获取数据
int id = rs.getInt("id");
String name = rs.getName("name");
//创建对象,赋值
emp = new Emp();
emp.setInt(id);
emp.setString(name);
//装载集合
list.add(emp);
//释放资源
finaly{
if(rs!=null){
rs.close(); //还有stmt\conn
}
}
}
}
Jdbc工具类——登录案例
需求:录入用户名和密码;判断用户是否登陆成功
1.创建数据库表user
CREATE TABLE USER{
id INT PRIMARY AUTO_INCREMENT,
username VARCHAR(32),
password VARCHAR(32)
}
public class JDBCDemo{
public static void main(String[] args){
//1.键盘输入
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名"); //密码也是
sc.nextLine();
//2.调用方法 login是非静态方法:所以要创建对象
boolean flag = new JDBCDemo().login(username,password);
if(flag){
System.out.println("登陆成功");
}else{
System.out.println("用户名或密码失败");
}
}
//登录方法
public boolean login(String username, String password){
if(username == null || password == null){
return false;
}
//连接数据库判断是否登陆成功
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//1.
conn = JDBCUtils.getConnection()
//2.
String sql = "select *from user where username = '"+username+"' and password = '"+password+"'";
//3.
stmt = conn.createStatement();
//4.
rs = stmt.executeQuery(sql);
//5.判断
return rs.next();
//要用finally
finally{
JDBCUtils.close(rs,stmt,conn);
}
return false;
}
}
【总结】
1.注册驱动也抽取,但一般不是放在一个方法里
2.抽取一个方法:获取连接对象
( 需求:不想传递参数麻烦,保证工具类的通用性:配置文件)
配置文件:properties url= user= password= driver=
【文件的读取,只需一次读取来得到值(getConnection ),使用静态代码块】
声明url user password三个静态成员变量
以及为了注册驱动:声明 private static String driver
静态代码块
static{
//读取资源文件,获取值 BufferReader FileReader 麻烦
//propeerties集合类
Properties pro = new Properties();
//获取src路径下的文件的方式-->ClassLoader 类加载器(加载进内存)
ClassLoader classloader = JDBCUtils.class.getClassLoader();
URL res = classloader.getResource("jdbc.properties);
String path = res.getPath();
System.out.println(path);
//有bug
//加载文件 load可接受reader 和 inputStream 字符流 字节流 麻烦~~
add(new FileReader(“src/jdbc.properties”)); 绝对路径
//获取数据,赋值
url = pro.getPeoperties("url"); /还有user password driver
//注册驱动
Class.forName(driver);
}
public static Connection getConnection(){
return DriverManager.getConnection(url,user,password);
}
3.抽取一个方法:释放资源
public static void close(Statement stmt,Connection conn){
if(conn!=null){ //当然还有stmt
conn.close(); //要try catch
}
}
**可以重载有三个参数的
PreparedStatement:执行sql对象
1.SQL注入问题: 用户随便输入dsbhv,输入密码:a’ or ‘a’ = 'a
select *from user where username = ‘dsbhv’ and passwoord = ‘a’ or ‘a’ == ‘a’;
2.解决SQL注入:使用preparedstatement对象(预编译sql: 参数使用?占位符)
后期使用preparedStatement来完成增删查改的操作
//1.导入jar包
//2.注入驱动
//3.获取数据库连接对象connection
//4.定义sql
? ?
//5.获取执行sql的对象
PreparedStatement pstmt = Connection.PreparedStatement(String sql)
//6.赋值?
setXxx(参数1,参数2);
//7.执行sql,接受返回结果,不需要传递sql
executeQuery();
//8.处理结果
//9.释放资源
事务管理
1.开启事务:setAutoCommit(boolean autoCommit): 调用参数false则开启
2.提交事务:commit() ----没有异常时
3.回滚事务: rollback() ----出现异常时
数据库连接池(数据源DataSource)
1.本质:一个(存放数据库连接的)容器
系统初始化—容器创建—容器申请连接对象
2. 基本实现
标准接口:DataSource java.sql包下的(一般由厂商实现:C3P0 Druid)
接口中的方法:获取getConnection()
归还Connection.close()
C3P0 数据库池连接技术
1.基本使用
*导入2个jar包
*定义配置文件:名称 c3p0.properties 或 c3p0-config.xml
路径 直接将文件放在src目录下
*创建数据库连接对象——核心对象 ComboPooledDataSource
*获取连接:getConnection
public class c3p0Domo1{
public static void main(String[] args){
//1.导包
//2.创建数据库连接池对象(使用了默认配置)
DataSource ds = ComboPooledSource();
Connection conn = ds.getConnection();
//3.打印
System.out.println(conn);
}
}
2.若指定配置文件
DataSource ds = new ComboPooledSource(“etherc3p0”)
3.当指定配置文件中的连接对象少:
if(i==5){
conn.close(); //归还连接
}
Druid
1.基本使用
*导包 druid-1.0.9.jar
*定义配置文件:是以properties形式的; 可叫任意名称,放在任意目录
*获取数据库连接池对象:通过工厂来获取 DruidDataSourceFactory
* 获取连接:getConnection()
//1.导包到lib目录下
//2.定义配置文件 druid.properties文件(文件里有参数) 放到src目录下
//3.加载配置文件
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//4.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource();
//5.获取连接
Connection conn = ds.getConnection();
System.out.println(conn);
Druid工具类
1.定义一个类 JDBCUtils
2.提供静态代码块加载配置文件,初始化连接池对象
3.提供方法
*获取连接方法:通过数据库连接池获取连接对象
*释放资源
*获取连接池的方法
public class JDBCUtils{
//定义成员变量
private static DataSource ds;
//静态代码块
static{
//1.加载配置文件
Properties pro = new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//2.获取DataSource
ds = DruidDataSourceFactory.createDataSource(pro);
}
//获取连接
public static Connection getConnection(){
return ds.getConnection();
}
//释放资源
public static void close(Statement stmt,Connection conn){
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close(); //归还连接
}
}
//释放资源的重载
public static void close(ResultSet rs,Statement stmt,Connection conn){
if...rs
if...stmt
if...conn //归还连接
}
//获取连接池方法
public static DataSource getDataSource(){
return ds;
}
}
注意:释放资源部分可以简化(含有重载)
//两个参数的
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}
//三个参数的
public static void close(ResultSet rs,Statement stmt,Connection conn){
if…rs;
if…stmt;
if…conn;
}
测试工具类 : 完成添加操作,给account表添加一条记录
public static void main(String[] args){
Connection conn = null;
PreparedStatement pstmt = null;
//1.获取连接
conn = JDBCUtils.getConnection();
//2.定义sql
String sql = "insert into account value(null,?,?)";
//3.获取pstmt对象
pstmt = conn.preparedStatement(sql);
//4.给问号赋值
pstmt.setString(1,"王五");
pstmt.setDouble(2,3000);
//5.执行sql
int count = pstmt.executeUpdate();
System.out.println(count);
//6.释放资源
finally{
JDBCUtils.close(pstmt,conn);
}
}
JdbcTemplate ----完成CRUD操作
- update(): 执行增删查改的DML操作
- queryForMap(): 查询结果将结果集封装到map集合
将列名作key 值作为value 将这条记录封装为一个map集合 - queryForList(): 查询结果将结果集封装到List集合
【注意】:将每条记录封装为一个Map集合,再将Map集合装载到List集合 - query(): 查询结果,将结果封装为JavaBean对象
*query的参数:RowMapper
*一般我们使用BeanPropertyRowMapper实现类,可以完成数据JavaBean的自动封装
* new BeanPropertyRowMapper<类型>(类型.class) - queryForObject(): 查询结果,将结果封装为对象
一般用于聚合函数的查询
1.快速入门
public static void main(String[] args){
//1.导入几个包
//2.创建JDBCTemplate对象
JDBCTemplate template = new JDBCTemplate(JDBCUtils.getDataSource());
//3.调用方法
String sql = "update account set balance = 5000 where id = ?";
int count = template.update(sql,3); //合并了执行SQL和设定值
System.out.println(count);
}
DML执行语句
0.Junit.Test单元测试—让方法独立执行
public static void main(String[] args){
@Test
public void test1(){
System.out.println("执行了…“);
//如果这里有错误 int i = 3/0; 会出现红色提示
}
@Test
public void test2(){
System.out.println("又被执行...")
}
}
1.修改1号数据的 salary 为 10000
***先创建一个Emp类
public static void main(String[] args){
//1.获取JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
@Test
public void test1(){
//2.定义sql
String sql = "update emp set salary = 10000 where id = 1";
//3.执行sql
int count = template.update(sql);
System.out.println(count);
}
@Test
test2(){
String sql = "insert into emp(id,ename,dept_id)values(?,?,?)";
int count = template.update(sql,001,"殷素素",10)
System
}
@Test
test3(){
String sql = "delete from emp where id = ?"
int count = template.update(sql,001)
System
}
}
2.添加一条记录
3.删除刚才添加的记录
DQL
4.查询id = 1所有的记录,将其封装为Map集合
@Test 4
String sql = "select *from emp where id = ?";
Map<String,Object> map = template.queryForMap(sql,001);
System.out.println(map);
@Test 5 【没有简化】
public void test5(){
String sql = "select *from emp";
List<Map><String,Object> list = template.queryForList(sql);
for(Map<String, Object> stringObjectMap : list){
System.out.println(stringObjectMap);
}
@Test 6.1
String sql = "select *from emp";
List<Emp> list = template.query(sql,new RowMapper<Emp>(){
@Override
public Emp mapRow(ResultSet rs,int i){
Emp emp = new Emp();
int id = rs.getInt("id");
String ename = rs.getString("ename");
Date joindate = rs.getDate("joindate");
emp.setId(id);
ename
emp.joindate(joindate);
return emp;
}
});
for(Emp emp : list){
System.out.println(emp);
}
@Test 6.2 用别人提供的实现类
public void test62(){
String sql = "select *from emp";
List<Emp> list = template.query(sql,new BeanPropertyRowMapper<Emp>(Emp.class));
for (Emp emp : list){
System.out.println(emp);
}
}
@Test7
public void test7(){
String sql = "select count(id) from emp"
Long total = template.queryForObject(sql,Long.class); //queryForObject是用来查询一些聚合函数
System.out.println(total);
}
5.查询所有记录,j将其封装为List
6.查询所有记录,将其封装为Emp对象的List集合
7.查询总记录数