1.JDBC
1.什么是JDBC?
JDBC(Java Database Connectivity) Java连接数据库,可以使用Java语言连接数据库实现增删改查操作
2.JDBC核心思想
Java中定义访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。由数据库厂商提供驱动实现类(Driver 数据库驱动)
3.环境搭建
1.在项目下新建lib文件,用于存放jar文件
2.将mysql驱动mysql-connector-java-5.1.7-bin.jar复制到项目的lib文件夹中
3.然后右键jar文件->Bulid Path->Add to Bulid Path
4.开发步骤
4.1连接数据库
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获得连接
String url="jdbc:mysql://localhost:3306/testJdbc";
String user="root";
String password="123456";
try {
Connection connection=DriverManager.getConnection(url, user, password);
if(connection!=null) {
System.out.println("连接到数据库了-------------");
}else {
System.out.println("连接失败--------------------------");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//1.注册驱动
Class.forName(“com.mysql.jdbc.Driver”);
//2.获得连接
String url=“jdbc:mysql://localhost:3306/testJdbc”;
String user=“root”;
String password=“123456”;
Connection connection=DriverManager.getConnection(url, user, password);
注:url:连接地址 jdbc:mysql: 协议 localhost:本机 3306:端口 testJdbc:数据库的名字
user:用户名
password:密码
(根据具体自己的情况)
只要有上面两个步骤,并且connection对象不为null,那么就证明连接数据库成功了!!!
4.2操作数据库(增删改)
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获得连接
String url="jdbc:mysql://localhost:3306/testJdbc";
String user="root";
String password="123456";
try {
Connection connection=DriverManager.getConnection(url, user, password);
if(connection!=null) {
System.out.println("连接到数据库了-------------");
}else {
System.out.println("连接失败--------------------------");
}
//3.获得执行SQL语句的对象
Statement statement=connection.createStatement();
//4.编写SQL语句,执行SQL语句
String sql="insert into Student(name,sex,age)values('小明','男',20)";//要用单引号
int result=statement.executeUpdate(sql);
System.out.println(result);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//3.通过Connection对象获得Statement对象,用于对数据库进行访问
Statement statement=connection.createStatement();
//4.编写SQL语句,执行SQL语句
String sql=“insert into Student(name,sex,age)values(‘小明’,‘男’,20)”;//要用单引号
int result=statement.executeUpdate(sql);//1 说明对数据库的操作成功,受影响行数为1行
4.3处理结果,释放资源
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获得连接
String url="jdbc:mysql://localhost:3306/testJdbc";
String user="root";
String password="123456";
try {
Connection connection=DriverManager.getConnection(url, user, password);
if(connection!=null) {
System.out.println("连接到数据库了-------------");
}else {
System.out.println("连接失败--------------------------");
}
//3.获得执行SQL语句的对象
Statement statement=connection.createStatement();
//4.编写SQL语句,执行SQL语句
String sql="insert into Student(name,sex,age)values('小红','女',20)";//要用单引号
int result=statement.executeUpdate(sql);
// System.out.println(result);
//5.处理接收结果
if(result==1) {
System.out.println("对数据库的操作成功");
}else {
System.out.println("对数据库的操作失败");
}
//6.释放资源
statement.close();
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//5.处理接收结果
if(result==1) {
System.out.println(“对数据库的操作成功”);
}else {
System.out.println(“对数据库的操作失败”);
}
//6.释放资源 先开后关
statement.close();
connection.close();
注:以上六个步骤就是连接数据库、访问数据库,关闭数据库的核心。。。。(增删改,都是这个步骤,唯一不同的就是SQL语句)
案例(查询操作)
package com.le.JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class QueryJDBC {
public static void main(String[] args) throws Exception {
//创建一个集合来存储多个Student对象
List <Student> list=new ArrayList<Student>();
try {
//1.注册驱动类
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/testJdbc", "root", "123456");
//3.创建Statement对象,用来发送SQL语句
Statement statement=connection.createStatement();
//4.执行SQL语句,并返回结果
String sql="select * from Student";
ResultSet resultSet=statement.executeQuery(sql);
//5.处理结果集
while(resultSet.next()) {//判断下一行是否有数据
/**
* 也可以选择resultSet.getInt(1);编号从1开始,不过更提倡列名的方式
*/
int id=resultSet.getInt("id");
String name=resultSet.getString("name");
String sex=resultSet.getString("sex");
int age=resultSet.getInt("age");
//创建一个Student对象来存储数据
Student stu=new Student(id,name,sex,age);
list.add(stu);
}
for(Object o:list) {
System.out.println(o);
}
//6.释放资源
resultSet.close();
statement.close();
connection.close();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
登录案例:
package com.le.JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class TestLogin {
public static void main(String[] args) throws Exception {
Scanner sc=new Scanner(System.in);
//1.注册驱动类
Class.forName("com.mysql.jdbc.Driver");
System.out.println("请输入用户名");
String username=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
//2.获取连接
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc", "root", "123456");
// if(connection!=null) {
// System.out.println("连接成功");
// }else {
// System.out.println("连接失败");
// }
//3.获取Statement对象,用来发送SQL语句
Statement statement = connection.createStatement();
//4.执行SQL语句,并获取返回结果
String sql="select username,password from user where username='"+username+"' and password='"+password+"'";
ResultSet resultSet=statement.executeQuery(sql);
//5.处理结果集
if(resultSet.next()) {
System.out.println("登录成功");
// System.out.println(resultSet.getString("username"));
}else {
System.out.println("登录失败");
}
//6.释放资源
resultSet.close();
statement.close();
connection.close();
}
}
上面这个登录的例子可以不用看。。。
注:这个 String sql=“select username,password from user where username=’”+username+"’ and password=’"+password+"’";可能会有SQL注入异常,所以PrepareStatement非常有必要。。。
PrepareStatement继承了Statement接口
PreparedStatement的作用:
1、预编译SQL语句,效率高
2.安全,避免SQL注入
3.可以动态的填充数据,执行多个同构的SQL语句
参数标记 ?
//1.预编译SQL语句
PreparedStatement pstmt=connection.prepareStatement(“select * from user where username=? and password=?”);
package com.le.JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class TestLogin2 {
public static void main(String[] args) throws Exception {
Scanner sc=new Scanner(System.in);
//1.注册驱动类
Class.forName("com.mysql.jdbc.Driver");
System.out.println("请输入用户名");
String username=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
//2.获取连接
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc", "root", "123456");
// if(connection!=null) {
// System.out.println("连接成功");
// }else {
// System.out.println("连接失败");
// }
//3.获取PreparedStatement对象,预编译SQL语句,动态绑定?,并为其赋值
PreparedStatement pstmt=connection.prepareStatement("select * from user where username=? and password=?");
pstmt.setString(1, username);
pstmt.setString(2, password);
System.out.println(pstmt);
//4.并获取返回结果
ResultSet resultSet=pstmt.executeQuery();
//5.处理结果集
if(resultSet.next()) {
System.out.println("登录成功");
// System.out.println(resultSet.getString("username"));
}else {
System.out.println("登录失败");
}
//6.释放资源
resultSet.close();
pstmt.close();
connection.close();
}
}
//3.获取PreparedStatement对象,预编译SQL语句,动态绑定?,并为其赋值
PreparedStatement pstmt=connection.prepareStatement(“select * from user where username=? and password=?”);
pstmt.setString(1, username);
pstmt.setString(2, password);
注:只有这两句不一样,其他的都一样。。。。
2.封装工具类
(重用性)------------------------------------------------------------------------------------------
jdbc的六个核心步骤:
1.加载驱动
2.获取连接对象
3.准备PreparedStatement对象,SQL 语句,.为占位符进行赋值
4.执行SQL语句,接收结果集,
5.处理结果集
6.关闭资源
注:上面1、2、6都是反复重复操作,所以可以将其封装成方法,调用即可。。。。
建议代码方式:
获取连接的方法 public static Connection getConnection(){};
释放资源的方法 public static void closeAll(Connection connection,Statement preparedStatement,ResultSet resultSet){};
package com.le.JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DbUtils {
static {
//1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");//为了让其自始自终只加载一次,把它放在静态代码块中
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取连接的方法
public static Connection getConnection() throws Exception {
//2.获取连接
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc", "root", "123456");
return connection;
}
//释放资源的方法
public static void closeAll(Connection connection,Statement preparedStatement,ResultSet resultSet) throws Exception {
if(resultSet!=null) {
resultSet.close();
}
if(preparedStatement!=null) {
preparedStatement.close();
}
if(connection!=null) {
connection.close();
}
}
}
跨平台性:--------------------------------------------------------------------------------------------
在src下新建db.properties文件。。。
package com.le.jdbc1;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DbUtils {
public static final Properties PROPERTIES=new Properties();//存储文件的map
static {
InputStream inputStream=DbUtils.class.getResourceAsStream("/db.properties");
try {
PROPERTIES.load(inputStream);
Class.forName(PROPERTIES.getProperty("driver"));
} catch (Exception e) {
// TODO Auto-generated catch block
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) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return connection;
}
//释放资源
public static void closeAll(Connection connection ,Statement statement,ResultSet resultSet) {
if(resultSet!=null) {
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(statement!=null) {
try {
statement.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();
}
}
}
}
注:这是上面代码块重要的部分
下面的代码块为测试类
package com.le.jdbc1;
import java.sql.Connection;
public class TestDbUtils {
public static void main(String[] args) {
Connection connection = DbUtils.getConnection();
if(connection!=null) {
System.out.println("连接数据库成功");
}else {
System.out.println("连接失败");
}
}
}
3.DAO数据访问对象(Data Acess Object)
DAO实现了业务逻辑和数据库访问相分离。
1,对同一张表的所有操作封装在xxxDaoImpl对象中
2.根据增删改查的不同功能实现具体的方法
package person;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class PersonDaoImpl {
//添加
public int insert(Person person) {
//1.获取连接
Connection connection=DBUtils.getConnection();
int result=0;
PreparedStatement pstmt=null;
try {
//2.准备PreparedStatement对象
pstmt=connection.prepareStatement("Insert into person(name,age,bornDate,email,address)values(?,?,?,?,?)");
//3.给占位符进行赋值
pstmt.setString(1, person.getName());
pstmt.setInt(2, person.getAge());
pstmt.setObject(3,person.getBornDate());
pstmt.setString(4, person.getEmail());
pstmt.setString(5, person.getAddress());
//4.执行SQL语句,并返回值
result=pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
DBUtils.closeAll(connection,pstmt, null);
}
return result;
}
//更新
public int update(Person person) {
//1.获取连接
Connection connection=DBUtils.getConnection();
int result=0;
PreparedStatement pstmt=null;
try {
//2.准备PreparedStatement对象
pstmt=connection.prepareStatement("update person set name=?,age=?,bornDate=?,email=?,address=? where id=?");
//3.给占位符进行赋值
pstmt.setString(1, person.getName());
pstmt.setInt(2, person.getAge());
pstmt.setObject(3,person.getBornDate());
pstmt.setString(4, person.getEmail());
pstmt.setString(5, person.getAddress());
pstmt.setInt(6, person.getId());
//4.执行SQL语句,并返回结果
result=pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
DBUtils.closeAll(connection, pstmt, null);
}
return result;
}
//删除
public int delete(int id) {
//1.获取连接
Connection connection = DBUtils.getConnection();
PreparedStatement pstmt=null;
int result=0;
try {
//2.准备PreparedStatement对象
pstmt=connection.prepareStatement("delete from person where id=?");
//3.给占位符进行赋值
pstmt.setInt(1, id);
//4.执行SQL语句,并返回结果值
result=pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
DBUtils.closeAll(connection, pstmt, null);
}
return result;
}
//查询
public Person select(int id) {
//1.获取连接
Connection connection=DBUtils.getConnection();
PreparedStatement pstmt=null;
ResultSet resultSet=null;
Person person=null;
try {
//2.准备PreparedStatement对象
pstmt=connection.prepareStatement("select * from person where id=?");
//3.给占位符进行赋值
pstmt.setInt(1, id);
//4.执行SQL语句,并返回结果值
resultSet=pstmt.executeQuery();
if(resultSet.next()) {
String name=resultSet.getString("name");
int age=resultSet.getInt("age");
Date bornDate=resultSet.getDate("bornDate");
String email=resultSet.getString("email");
String address=resultSet.getString("address");
person=new Person(name, age, bornDate, email, address);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
DBUtils.closeAll(connection, pstmt, resultSet);
}
return person;
}
//查询所有
public List<Person> selectAll(){
//1.获取连接
Connection connection=DBUtils.getConnection();
List<Person> list=new ArrayList<Person>();
PreparedStatement pstmt=null;
ResultSet resultSet=null;
Person person=null;
try {
//2.准备PreparedStatement对象
pstmt=connection.prepareStatement("select * from person ");
//4.执行SQL语句,并返回结果值
resultSet=pstmt.executeQuery();
while(resultSet.next()) {
int id=resultSet.getInt("id");
String name=resultSet.getString("name");
int age=resultSet.getInt("age");
Date bornDate=resultSet.getDate("bornDate");
String email=resultSet.getString("email");
String address=resultSet.getString("address");
person=new Person(id,name, age, bornDate, email, address);
list.add(person);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
DBUtils.closeAll(connection, pstmt, resultSet);
}
return list;
}
}
4.Date工具类
数据库中存储的数据类型为java.sql.Date。而Java应用层存储日期类型为java.util.Date,所以当我们用Java应用层的程序 插入 (比如上段代码中的插入方法) 带有日期的数据到数据库时,需要进行转换。
1.java.util.Date
Java语言常规应用层面的日期类型,可以通过字符串创建对应的时间对象,无法直接通过JDBC插入到数据库
2.java.sql.Date
不可以通过字符串创建对应的时间对象,只能通过毫秒值创建对象(1970年至今的毫秒值),可以通过JDBC插入到数据库
package person;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class DateUtils {
private static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM");
//1.字符串转换为util.Date
public static java.util.Date toUtilDate(String str){
// SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM");
java.util.Date utilDate=null;
try {
utilDate = sdf.parse(str);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return utilDate;
}
//2.util.Date转换为sql.Date
public static java.sql.Date toSqlDate(java.util.Date date ){
long times=date.getTime();
java.sql.Date sqlDate=new java.sql.Date(times);
return sqlDate;
}
//3.util.Date转换为字符串的形式
public static String toStingDate(java.util.Date date) {
// SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM");
String stringDate=sdf.format(date);
return stringDate;
}
}
在上一个知识点中插入日期到数据库中的步骤就是:
1、日期是一个String类型 1999-01-01
2.在插入方法中,转换为util.Date
Person person=new Person("张",23,DateUtils.toUtilDate("1999-01-01"),"2678@qq.com","山东");
3.在PreparedStatement 中设置把util.Date转换成sql.Date
pstmt.setDate(3,DateUtils.toSqlDate(person.getBornDate()));
5.Service业务逻辑层
业务逻辑层是完成业务的,它是调用数据库访问层中的一个或多个方法。
package person;
public class PersonServiceImpl {
//注册
public void register(Person person) {
PersonDaoImpl personDao=new PersonDaoImpl();
//1.查询是否存在注册账户
Person person2 = personDao.select(person.getName());
if(person2==null) {
//2.不存在就新增
personDao.insert(person);
System.out.println("注册成功");
}else {//3,存在就返回
System.out.println("注册失败");
}
}
}
7.三层架构
1.表示层:
命名XXXView
职责:收集用户的数据和需求,展示数据(概括来说就是与用户打交道,让用户输入数据之类的操作)
2.业务逻辑层
命名:XXXServiceImpl
职责:数据加工处理,调用数据库访问层中的方法完成业务的实现,控制事务(一个业务的实现可能要调用数据库访问层中一个或多个方法)
3.数据库访问层
命名:XXXDaoImpl
职责:向业务层提供数据,将业务层加工后的数据同步到数据库中(总的来说,就是对数据库中表的操作,增删改查)
可以分别给这三层定义接口,为什么呢?比如当你定义了数据库访问层的接口,然后再让XXXDaoImpl 实现该接口,这样如果你再定义XXXDaoImpl2,实现该接口,就避免了你定义的方法不一致,需要在XXXServiceImpl做大量修改。好处就是你直接可以在XXXServiceImpl中
DaoInterface accountDao=new AccountDaoImpl();
直接改成
DaoInterface accountDao=new AccountDaoImpl2();
不需要做其他的操作。
注:其他层定义接口,用处都是一样,避免大量代码的更改。。。
三层架构项目的搭建
utils包存放工具类
entity包存放实体类
dao包存放dao接口,在dao包下的impl包存放的是dao接口实现类
service包存放service接口,在service包下的impl包存放的是service接口实现类
view包存放的是显示的,(main方法)
注:dao、service、view就是三层架构。。。。