概述:
一般客户端(其他程序)操作数据库的流程
通过账号和密码连接数据库
将编写好的sql语句传递到数据库执行
数据库执行sql语句然后返回客户端
java中主要通过JDBC进行数据库操作
JDBC为java连接数据库提供了一个规范
不同的数据库厂商根据JDBC规范提供对应连接自家数据库驱动服务
在java程序员连接所有数据库的代码都是一样的,因为调用是接口的规范,但是不同的厂商底层实现的规范不一样
连接mysql需要下载对应驱动
JDBC的API
类型 | 权限定名 | 简介 |
---|---|---|
class | java.sql.DriverManager | 管理多个数据库驱动类,提供了获取数据库连接的方法 |
interface | java.sql.Connection | 代表一个数据库连接(当connection不是null时,表示已连接数据库) |
interface | java.sql.Statement | 发送SQL语句到数据库工具 |
interface | java.sql.ResultSet | 保存SQL查询语句的结果数据(结果集) |
class | java.sql.SQLException | 处理数据库应用程序时所发生的异常 |
JDBC的基本开发流程
将驱动拷贝到工程中,并且被工程依赖
连接数据库
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/testdb?serverTimezone=GMT%2B8",//8需要设置时区
//"jdbc:mysql://localhost:3306/testdb?useUnicode=TRUE&characterEncoding=UTF-8",//5.X解决乱码问题
"root",
"123"
);
url连接数据的路劲
jdbc: mysql: //localhost:3306 /testdb
协议名称 连接厂商 连接地址ip+端口 连接的数据库名称
获取发送对象
Statement statement = connection.createStatement();
发送sql语句并且获得返回结果
//4 ,发送sql语句
int result = statement.executeUpdate("insert into tb_user values (null,'少年',1)");
//5,结果是受到影响的函数
System.out.println("结果:"+result);
关闭连接(默认情况下,mysql的连接是有限制的,超过就会没有连接了)
//关闭连接
connection.close();
JDBC查询操作
executeUpdate可以支持增,删,改;返回的结果是int类型,受影响的函数
需要使用executeQuery进行查询;返回结果是ResultSet
基本的代码
//1,加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2,通过url,账号和密码打开连接
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC",
"root",
"123"
);
//3,创建statement
Statement statement = connection.createStatement();
//4,执行sql语句
ResultSet rs = statement.executeQuery("select * from tb_user");
while(rs.next()){
//将rs向后移动,如果有数据,那么则返回true
//可以获取一行记录的值
int id = rs.getInt(1);
String uname = rs.getString(2);
int rid = rs.getInt(1);
System.out.println(id+":"+uname+":"+rid);
}
//5.关闭连接
rs.close();
statement.close();
connection.close();
一般查询需要将结果封装到实体类或者集合中,便于其他的类调用
创建储存数据的实体类
public class UserEntity {
int uid;
String uname;
int rid;
}
将数据封装到实体类中
//创建一个集合存储所有用户的信息
List<UserEntity> list = new ArrayList<>();
while(rs.next()){
//将rs向后移动,如果有数据,那么则返回true
//可以获取一行记录的值
int id = rs.getInt(1);
String uname = rs.getString(2);
int rid = rs.getInt(1);
//创建一个对象
UserEntity userEntity = new UserEntity(id,uname,rid);
list.add(userEntity);
}
日期如果设置
在java代码中,一般都是使用java.util.Data类储存日期格式
插入日期的实现(转换成字符串插入即可)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateStr = sdf.format(userEntity.getBirthday());
int result = statement.executeUpdate("insert into tb_user values (null,'"+userEntity.getUname()+"',1,'"+dateStr+"')");
查询结果,可以直接将sql.Date强制转换成java.util.Data
java.util.Date date = rs.getDate("birthday");
登录案例
在数据中创建一个项目的数据库
create database db001
在idea创建连接数据库,并且创建一个表
-- 创建一个用户表
create table tb_user(
uid int primary key auto_increment,
uname varchar(50),
upwd varchar(50),
birthday date
)
创建一个表对应的实体类
public class UserEntity {
Integer uid;
String uname;
String upwd;
Date birthday;
}
将驱动包导入到项目的libs目录下,并且在project structure下进行依赖
实现UserDao
//实现插入的方法
public void insert(UserEntity userEntity){
Connection connection = null;
Statement statement = null;
//1,加载驱动包
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//2,打开连接
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/db001?serverTimezone=UTC",
"root",
"123"
);
//3,创建statement
statement = connection.createStatement();
//4,执行sql语句
String name = userEntity.getUname();
String pwd = userEntity.getUpwd();
String sql ="insert into tb_user values(null,'"+name+"','"+pwd+"','2010-10-1')";
//5,处理返回,关闭连接
int res = statement.executeUpdate(sql);
if(res>0){
System.out.println("插入成功");
}else
System.out.println("插入失败");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
if (statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
//根据账号查询
public UserEntity login(String name,String pwd){
Connection connection;
Statement statement;
//1,加载驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//打开连接
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/db001?serverTimezone=UTC",
"root",
"123"
);
//3,创建statement
statement = connection.createStatement();
//4,执行sql语句
String sql ="select * from tb_user where uname='"+name+"'"
+" and upwd = '"+ pwd +"'";
System.out.println(sql);
ResultSet rs = statement.executeQuery(sql);
//5,处理返回结果
if(rs.next()){
int uid = rs.getInt("uid");
String uname = rs.getString("uname");
String upwd =rs.getString("upwd");
Date birthDay = rs.getDate("birthday");
UserEntity userEntity = new UserEntity(uid,uname,upwd,birthDay);
return userEntity;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
测试代码
public static void main(String[] args) {
UserDao userDao = new UserDao();
UserEntity userEntity = userDao.login("小黄","12344' or '1' = '1");
if (userEntity!=null){
System.out.println("登录成功");
System.out.println(userEntity.toString());
}else{
System.out.println("登录失败");
}
}
public static void main1(String[] args) {
UserDao userDao = new UserDao();
UserEntity userEntity = new UserEntity(null,"小黄","123",new Date());
userDao.insert(userEntity);
}
sql注入的问题
由于数据的操作是使用的字符串进行拼接完成的,这样就导致sql语句注入的问题
select * from tb_user where uname='小黄' and upwd = '12344' or '1' = '1'
在实现dao操作的时候,最好不要使用sql拼接,jdbc提供了一个预编译的功能,来解决sql注入的问题
//3,创建一个预编译
String sql = "select * from tb_user where uname = ? and upwd = ?";
//仅仅判断语法
PreparedStatement ps = connection.prepareStatement(sql);
//将需要插入的值放入
ps.setString(1,name);
ps.setString(2,pwd);
使用DBUtil封装操作
创建一个DButil工具
public class DBUtil { static{ //1加载驱动 try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //2,打开连接的方法 public static Connection getConn(){ try { return DriverManager.getConnection( "jdbc:mysql://localhost:3306/db001?serverTimezone=UTC", "root", "123" ); } catch (SQLException throwables) { throwables.printStackTrace(); } return null; } //3,关闭连接的方法 public static void close(Connection conn, PreparedStatement ps, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(ps!=null){ try { ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } }
在Dao中使用工具类
//实现更新操作
public void update(UserEntity userEntity){
//1,打开连接
Connection connection = DBUtil.getConn();
//2,创建预编译
String sql ="update tb_user set uname=?,upwd=?,birthday=? where uid=?";
PreparedStatement ps;
try {
ps = connection.prepareStatement(sql);
//设置参数
ps.setString(1,userEntity.getUname());
ps.setString(2,userEntity.getUpwd());
long time = userEntity.getBirthday().getTime();//获取时间戳
//需要将java.util.Date 转换成java.sql.Date;
java.sql.Date date = new Date(time);
ps.setDate(3,date);
ps.setInt(4,userEntity.getUid());
//执行操作
int result = ps.executeUpdate();
if(result>0){
System.out.println("修改成功");
}else{
System.out.println("修改失败");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
引入properiter可以自定义jdbc的参数
在src目录下创建db.properties配置文件
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/db001?serverTimezone=UTC
name = root
password=123
在DButil中加载配置文件
static String driver;//驱动
static String username;//用户名
static String url; //连接url
static String password;//密码
static{
//加载properties
Properties ps = new Properties();
//加载配置
try {
ps.load(DBUtil.class.getClassLoader().getResourceAsStream("db.properties"));
driver = ps.getProperty("driver");
username = ps.getProperty("name");
url = ps.getProperty("url");
password = ps.getProperty("password");
} catch (IOException e) {
e.printStackTrace();
}
//1加载驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}