简介
JDBC:数据库连接,是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java编写的类和接口组成。
使用步骤
1.引入jar文件.
2.加载数据库驱动(JavaSE项目中可以省略,Javaweb项目必须编写此步骤)
class.forName ("com.mysq1.jdbc.Driver");
3.通过驱动管理器,获取JDBC连接对象.
connection conn = DriverManager.getConnection("数据库连接地址", "帐号", "密码");
//数据库连接地址格式:主协议:子协议://ip地址:端口号/数据库名称
//mysql的连接地址: jdbc:mysql://loca1host: 3306/java35
//oracle的连接地址: jdbc:oracle:thin:@loca7host:1521:ORCL
4.通过连接对象,创建SQL执行对象(SQL执行环境)
statement state = conn. createstatement();
5.通过SQL执行对象﹑,执行sQL语句.
state.execute(string sq1语句)
6.释放资源
state.close();
conn.close();
public class Demo1 {
public static void createTable() throws ClassNotFoundException, SQLException {
/*
加载数据库驱动
mysql6以下驱动:com.mysql.jdbc.Driver
mysql6及以上驱动:com.mysql.cj.jdbc.Driver
*/
Class.forName("com.mysql.jdbc.Driver");
/*
通过驱动管理器,获取JDBC连接对象
数据库连接地址:主协议:子协议://ip地址:端口号/数据库名
*/
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test02", "root", "");
//通过连接对象,创建SQL执行对象
Statement state = conn.createStatement();
/*
state.execute():
执行任何SQL语句,返回值不代表SQL执行是否成功或者失败
如果有结果集就返回true,没有结果集合返回false
state.executeQuery():
执行后返回查询的结果集
state.executeUpdate():
返回SQL语句影响的行数
*/
ResultSet resultSet = state.executeQuery("select * from msg");
while (resultSet.next()){
int id = resultSet.getInt("id");
String number = resultSet.getString("学号");
String name = resultSet.getString("姓名");
System.out.println(id+" "+number+" "+name);
}
//释放资源
resultSet.close();
state.close();
conn.close();
}
}
1 111 vv
2 222 qq
3 333 aa
SQL注入问题
当我们在实现登录功能的时候,需要根据用户输入的账户密码,在数据库中查找是否存在该用户的信息。
我们的查询语句可能是这样
state.executeQuery("select * from xzk_user where username='"+username+"' and password='"+password+"'");
但是如果我们输入的username="zhangsan",password=" 1'or'1'='1' "时,SQL语句就变成了
state.executeQuery("select * from xzk_user where username='zhangsan' and password='1' or '1'='1'");
or 后面的那个式子就是个永真式
解决方法:将代码与参数分离
PreparedStatement
原理:
1. 将未拼接参数的SQL语句, 作为SQL指令, 先传递给数据库进行编译.
2. 再将参数传递给数据库, 此时传递的参数不会再作为指令执行, 只会被当作文本存在
PreparedStatement 与 Statement 谁的性能高 ?看是什么数据库
在mysql中, preparedStatement原理是拼接SQL, 所以Statement性能高.
在Oracle中, preparedStatement原理是对SQL指令进行预处理, 再传递的参数不具备特殊含义.有更好的SQL缓存策略,PreparedStatement高.
JDBC事务操作
- 开启事务: conn.setAutoCommit(false);(自动是每次执行SQL都会提交一次事务)
- 回滚事务: conn.rollback();
- 提交事务: conn.commit();
数据库连接池
Properties 作为配置文件
文件内容都是字符串 , 键与值之间通过等号连接 , 多个键值对之间换行分割 .例如 :url=xxxuser=xxxpassword=xxx
将文件转化为集合的步骤
-
创建Properties对象 :Properties ppt = new Properties();
-
创建一个字节输入流指向.properties文件:InputStream is = new FileInputStream("文件地址");
-
将字节输入流, 传递给properties对象, 进行加载:ppt.load(is);
连接池的使用
连接池用于缓存连接
使用连接池中的连接对象操作数据库时, 操作完毕依然需要释放连接(调用close()).
连接池中的连接在设计时, 使用了动态代理设计模式+装饰者设计模式 . 我们调用它的close方法, 代理没有关闭这个连接, 而是将连接重新放入了池中.
druid连接池的使用步骤
- 引入相关的jar文件:druid-1.0.9.jar
- 将配置文件引入
- 将配置文件, 转换为Properties对象: Properties ppt = new Properties(); ppt.load(配置文件的输入流);
- 通过连接池的工厂类(DruidDataSourceFactory)的创建连接池的方法(createDataSource()) :DataSource ds = DruidDataSourceFactory.createDataSource(ppt);
- 从连接池中 获取连接对象:Connection conn = ds.getConnection();
工具类
public class DruidUtil {
private static DataSource ds;//连接池
static {
Properties ppt = new Properties();//配置文件
try {
ppt.load(DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(ppt);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从连接池中取出一个连接
*/
public static Connection getConnection(){
try {
return ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 释放资源
*/
public static void close(Connection conn, Statement state, ResultSet rs){
try {
conn.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
try {
state.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
try {
rs.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
}
}
实例:使用JDBC实现多表查询 ***
1、一对多关系
学生表和年级表,学生是多的那方,年级是一的那方。
数据库是通过外键列来维持两个表的关系,实体类是通过属性来维持两表关系。在建立一对多关系时,我们在一方的属性里面加一个多方的一个属性。口诀:一方存多方的集合,多方存一方的对象
查询数据库代码:
2、多对一关系
在上面的基础上,我们需要在多方添加一方的对象,多方存一方的对象
3、多对多关系
多对多关系必须是基于三张表实现的。比如菜单表和角色表,某个功能菜单可以分配给多个角色,某个角色可以拥有多个菜单。
中间表不需要声明实体类,多方存另一方的集合