目录
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
JDBC相关API
注册驱动程序:Class.forName("com.mysql.jdbc.Driver");
代码分析:使用反射机制,将字节码文件加载至内存,返回一个Class对象。该类中定义了一个静态代码块,作用就是注册驱动,所以无需返回对象。(mysql5之后可以省略)
DriverManager类:驱动管理对象
static Connection getConnection(String url, String user, String password) 获取数据库的连接
如果连接的是本地数据库,并且端口号是3306,则url可以简写成: jdbc:mysql:///数据库名称
Connection:数据库连接对象
获取执行SQL的对象
- Statement createStatement()
- PreparedStatement prepareStatement(String sql)
管理事务
- 开启事务:setAutoCommit(boolean autoCommit) 参数为false为开启事务
- 提交事务:commit()
- 回滚事务:rollback()
Statement:执行sql的对象
- int executeUpdate(String sql):执行DML、DDL语句 返回值是影响行数
- ResultSet executeQuery(String sql) :执行DQL(select)语句
ResultSet:结果集对象,封装查询结果
- boolean next():游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据)
- getXxx(参数):获取数据 参数可以是列的编号(从1开始),也可以是列的名称
PreparedStatement:执行sql的对象
SQL注入问题
在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
1. 输入用户随便,输入密码:a' or 'a' = 'a
2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'
预编译的SQL:参数使用?作为占位符,解决了SQL注入问题
- PreparedStatement Connection.prepareStatement(String sql) 获取执行SQL语句对象
- 使用setXxx(参数1,参数2) 给占位符赋值,参数1:位置编号,参数2:数据
- 执行sql语句,并返回查询结果 excuteQuery()或者excuteUpdate()
示例代码:SQL注入
public static void main(String[] args) throws ClassNotFoundException, SQLException {
System.out.println("请输入用户名:");
Scanner in = new Scanner(System.in);
String name = in.nextLine();
System.out.println("请输入密码:");
String password = in.nextLine();
Class.forName("com.mysql.jdbc.Driver");//注册驱动
Connection connection = DriverManager.getConnection("jdbc:mysql:///db_6", "root", "110120");//获取连接对象
String sql="select* from user2 where username='"+name+"'and password='"+password+"'";
System.out.println(sql);//select* from user2 where username='asd'and password='a' or 'a'='a' SQL注入问题,条件判断永远为真,查询的是全表
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()){//判断下一行是否有数据
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
statement.close();//释放资源
connection.close();//释放资源
}
//PreparedStatement 解决了SQL注入
public static void main(String[] args) throws ClassNotFoundException, SQLException {
System.out.println("请输入用户名:");
Scanner in = new Scanner(System.in);
String name = in.nextLine();
System.out.println("请输入密码:");
String password = in.nextLine();
Class.forName("com.mysql.jdbc.Driver");//注册驱动
Connection connection = DriverManager.getConnection("jdbc:mysql:///db_6", "root", "110120");//获取连接对象
String sql="select * from user2 where username=? and password=?";//含有占位符的sql语句
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,name);//给占位符赋值
statement.setString(2,password);
ResultSet resultSet = statement.executeQuery();
if(resultSet.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
statement.close();
connection.close();
}
案例:使用事务
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");//注册驱动
Connection connection = DriverManager.getConnection("jdbc:mysql:///db_6", "root", "110120");//获取连接对象
connection.setAutoCommit(false);//开启事务
String sql1="update account set balance= balance-500 where id=1";
String sql2="update account set balance= balance+500 where id=2";
Statement statement = connection.createStatement();
statement.executeUpdate(sql1);
int i=1/0;//制造错误
statement.executeUpdate(sql2);
connection.commit();//提交事务
connection.rollback();//事务回滚
statement.close();
connection.close();
}
数据库连接池
连接池:其实就是一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
好处:
- 节约资源
- 用户访问高效
实现数据库连接池的方法 标准接口DataSource
相关方法:
- getConnection():获取连接
- close():归还连接
C3P0数据库连接池
步骤:
- 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar 还有数据库驱动jar包
- 定义配置文件:c3p0-config.xml 直接将文件放在src目录下即可
- 创建核心对象 数据库连接池对象 ComboPooledDataSource
- 获取连接: getConnection
示例代码
配置文件 :可以进行多个数据库配置(一般使用默认)
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db_1</property>
<property name="user">********</property>
<property name="password">********</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">10</property>
<property name="checkoutTimeout">3000</property>
</default-config>
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db_1</property>
<property name="user">********</property>
<property name="password">********</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
测试代码
public static void main(String[] args) throws SQLException {
DataSource dataSource = new ComboPooledDataSource();//建立对象,使用默认配置
DataSource otherc3p0 = new ComboPooledDataSource("otherc3p0");//建立对象,使用名为otherc3p0的配置
Connection connection = dataSource.getConnection();//获得连接
connection.close();//归还连接
}
Druid数据库连接池
步骤
- 导入jar包 druid-1.0.9.jar
- 定义配置文件:properties形式、可以叫任意名称,可以放在任意目录下
- 加载配置文件
- 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
- 获取连接:getConnection
示例代码
配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db_1
username=********
password=********
initialSize=5
maxActive=10
maxWait=3000
测试代码
public static void main(String[] args) throws Exception {
Properties properties = new Properties();//连接Properties对象
properties.load(test22.class.getResourceAsStream("druid.properties"));//加载文件
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);//通过工厂类 获得DataSource对象、
Connection connection = dataSource.getConnection();//获取连接
connection.close();//归还连接
}
创建工具类:
- 在静态代码块中创建数据库连接池对象
- 成员方法:获取连接、释放资源、获取连接池对象
Spring JDBCTemplate
Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
创建JdbcTemplate对象。依赖于数据源DataSource。
成员方法
- update(sql,args...):执行DML语句。增、删、改语句
- queryForObject:查询结果,将结果封装为对象 (多个结果)
- query():查询结果,将结果封装成对象(单个结果)
- queryForList():查询结果将结果集封装为list集合
- 将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
示例代码
public static void main(String[] args) throws Exception {
Properties properties = new Properties();//连接Properties对象
properties.load(test22.class.getClassLoader().getResourceAsStream("druid.properties"));//加载文件
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);//通过工厂类 获得DataSource对象、
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql1="insert into user2 values(?,?)";
jdbcTemplate.update(sql1,"张三","123456789");//添加数据
String sql2="select * from user2";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql2);//将集合封装成list 一行一行的读取{username=tom, password=123}
for (Map<String, Object> map : maps) {
System.out.println(map);
}
List<user> query = jdbcTemplate.query(sql2, new BeanPropertyRowMapper<>(user.class));//将多个结果封装成对象
for (user user : query) {
System.out.println(user);
}
String sql3="select * from user2 where username='张三'";
user user = jdbcTemplate.queryForObject(sql3, new BeanPropertyRowMapper<>(user.class));//将单个结果封装成对象
System.out.println(user);
}