JDBC
1、概念:
Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的
即Java语言操作数据库。
2、入门步骤:
前提导入驱动jar包
1、注册驱动
2、获取数据库连接对象 Connection
3\定义sql
4、获取执行sql的语句对象 Statement
5、执行sql语句,接受返回结果
6、处理结果
7、释放资源
public class JdbcDemo {
public static void main(String[] args) {
try {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2\获取数据库连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db2", "root", "root");
//3\定义sql语句
String sql = "update stu set name = 'li' where id = 1";
//4\获取执行sql的对象 statement
Statement statement = connection.createStatement();
//5\执行sql
int count = statement.executeUpdate(sql);
//6\处理结果
System.out.println(count);
//7\释放资源
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、详解各个对象
a、DriverManager--驱动管理对象
功能:
1注册驱动
static void registerDriver(Driver driver) 注册与给定的驱动程序 DriverManager 。
写代码使用:Class.forName("com.mysql.jdbc.Driver");
通过查看源代码发现:在com.mysql.jdbc.Driver类中存在静态代码块
try
{
DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
2获取数据库连接
方法:static Connection getConnection(String url, String user, String password )
参数
url - 形式为 jdbc:subprotocol:subname的数据库网址
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
例子:jdbc:mysql://127.0.0.1:3306/db2
user - 正在连接的数据库用户 password - 用户密码
b、Connection--数据库连接对象
1\获取执行sql的对象
Statement createStatement() 创建一个 Statement对象,用于将SQL语句发送到数据库。
PreparedStatement prepareStatement(String sql) 创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。
2、管理事务:
开启事务:setAutoCommit(boolean autoCommit) --调用该方法设置参数为false,即开启事务。
提交事务:commit()
回滚事务:rollback()
c、Statement--执行sql的对象
1\执行sql
1\boolean execute(String sql) :可以执行任意的sql 了解
2、int executeUpdate(String sql) :可以执行DML(insert\update\delete)语句、DDL(create\alter\drop)语句
返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则成功,反之,则失败。
3、ResultSet executeQuery(String sql) :执行DQL(select)语句
d、ResultSet--结果集对象
1、next() 游标向下移动一行
2、getxxx(参数):获取数据
xxx:代表数据类型 如:int getInt(),String getString()
1、int --代表列的编号,从1开始 如:getString(1)
while (rs.next()){
System.out.println(rs.getInt(1)+","+rs.getString(2)+","+rs.getString(3));
}
2、String--代表列名。如:getString("name")
while (rs.next()){ System.out.println(rs.getInt("id")+rs.getString("name")+rs.getString("phone_num"));
public class JdbcDemo01 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取数据库连接对象
connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db2", "root", "root");
//定义sql语句
String sql = "select * from person";
//获取执行sql的statement对象
statement = connection.createStatement();
//执行sql语句
ResultSet rs = statement.executeQuery(sql);
//处理结果集
while (rs.next()){
Person person = new Person();
person.setId(rs.getInt("id"));
person.setName(rs.getString("name"));
person.setAge(rs.getInt("age"));
System.out.println(person);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e){
e.printStackTrace();
}
}
}
Jdbc工具类——练习
public class JdbcUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
static {
//1、创建properties集合类
Properties properties = new Properties();
try {
//2、加载文件
//获取src路径下的文件的方式--ClassLoader 类加载器
ClassLoader classLoader = JdbcUtils.class.getClassLoader();
// InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties");//返回用于读取指定资源的输入流。
// properties.load(resourceAsStream);
URL resourceUrl = classLoader.getResource("jdbc.properties");
String urlPath = resourceUrl.getPath();
System.out.println(urlPath);
properties.load(new FileReader(urlPath));
//3、获取配置的数据,赋值
JdbcUtils.url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
driver = properties.getProperty("driver");
//4、加载驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/***
* @Author 俺家笨丫头
* @Description: 获取数据库连接
* @Date: 2020/5/15 23:52
* @Param []
* @throws Exception
* @return java.sql.Connection
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
/**
* @Author 俺家笨丫头
* @Description: 释放资源
* @Date: 2020/5/15 23:52
* @Param [statement, connection]
* @throws Exception
* @return void
*/
public static void close(Statement statement, Connection connection){
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet rs, Statement statement, Connection connection){
if (rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public class JdbcDemo02 {
public static void main(String[] args) {
List<Person> personList = findAll();
System.out.println(personList);
System.out.println(personList.size());
}
private static List<Person> findAll() {
ArrayList<Person> list = new ArrayList<>();
String sql = "select * from person";
Connection connection = null;
try {
connection = JdbcUtils.getConnection();
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(sql);
while (rs.next()){
Person person = new Person();
person.setId(rs.getInt("id"));
person.setName(rs.getString("name"));
person.setAge(rs.getInt("age"));
list.add(person);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}
登录小练习(有bug)sql注入问题
public class Demo03 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名字:");
String name = scanner.next();
System.out.println("请输入密码:");
String password = scanner.next();
boolean b = logIn(name, password);
if(b){
System.out.println("登录成功");
}else{
System.out.println("用户名或密码错误");
}
}
private static boolean logIn(String name, String password) {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
if (name == null || password == null){
return false;
}
String sql = "select * from users where name = '" +name+
"' and password = '" + password +
"'";
System.out.println("sql:" + sql);
try {
connection = JdbcUtils.getConnection();
connection.setAutoCommit(true);
statement = connection.createStatement();
rs = statement.executeQuery(sql);
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs,statement,connection);
}
return false;
}
}
e、PreparedStatement--执行sql的对象
-
表示预编译的SQL语句的对象。
SQL语句已预编译并存储在
PreparedStatement
对象中。 然后可以使用该对象多次有效地执行此语句。1、SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
1、用户随便输入密码:a' or 'a' = 'a'
2、sql:select * from users where name = 'huhu' and password = 'a' or 'a' = 'a'
2、解决sql注入问题:使用PreparedStatement对象来解决
3、预编译的sql:参数使用?作为占位符
4、步骤:
1、导入驱动架包mysql-connector-java-5.1.40-bin.jar
2、注册驱动
3、获取数据库连接对象
4、定义sql
注意sql的参数使用?作为占位符。如 :select * from users where name = ? and password = ?;
5、获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
6、给?赋值
方法:setXXX(参数1,参数2)
参数1--?的位置编号 从1开始
参数2--?的值
7、执行sql,接受返回结果
8、处理结果
9、释放资源
public class Demo04 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名字:");
String name = scanner.next();
System.out.println("请输入密码:");
String password = scanner.next();
boolean b = logIn(name, password);
if(b){
System.out.println("登录成功");
}else{
System.out.println("用户名或密码错误");
}
}
private static boolean logIn(String name, String password) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet rs = null;
if (name == null || password == null){
return false;
}
try {
connection = JdbcUtils.getConnection();
connection.setAutoCommit(true);
String sql = "select * from users where name = ? and password = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,name);
preparedStatement.setString(2,password);
rs = preparedStatement.executeQuery();
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs,preparedStatement,connection);
}
return false;
}
}
4、JDBC控制事务:
1、事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
2、操作:开启事务、提交事务、回滚事务。
3、使用connection对象来管理事务
开启事务:setAutoCommit(boolean autoCommit) --调用该方法设置参数为false,即开启事务。
提交事务:commit()
回滚事务:rollback()
默认的话为自动提交, 每执行一个update ,delete或者insert的时候都会自动提交到数据库,无法回滚事务。 设置connection.setautocommit(false);
只有程序调用connection.commit()
的时候才会将先前执行的语句一起提交到数据库,这样就实现了数据库的事务。
true
:sql命令的提交(commit)由驱动程序负责 false
:sql命令的提交由应用程序负责,程序必须调用commit或者rollback方法
public class Demo05 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
PreparedStatement preparedStatement2 = null;
try {
//获取数据库连接
connection = JdbcUtils.getConnection();
//开启事务
connection.setAutoCommit(false);
//sql语句
String sql1 = "update person a set a.age = a.age - ? where a.id = ?";
String sql2 = "update person a set a.age = a.age + ? where a.id = ?";
//获取执行sql的对象
preparedStatement = connection.prepareStatement(sql1);
preparedStatement2 = connection.prepareStatement(sql1);
//设置参数
preparedStatement.setInt(1,5);
preparedStatement.setInt(2,1);
preparedStatement2.setInt(1,5);
preparedStatement2.setInt(2,5);
//执行sql
preparedStatement.executeUpdate();
int i = 3/0;//制造异常
preparedStatement2.executeUpdate();
//提交事务
connection.commit();
} catch (Exception e) {
if (connection != null){
try {
connection.rollback();//回滚事务
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
}finally {
JdbcUtils.close(preparedStatement,connection);
JdbcUtils.close(preparedStatement2,connection);
}
}
}
5、数据库连接池
A、概念:其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好之后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从 容器中获取连接对象,用户访问完后,会将连接对象归还给容器。
B、优点:1、节约资源 2、用户访问高效
C、实现:
1、标准接口:DataSource javax.sql包下
方法:
a、获取连接:getConnection()
b、归还连接:如果连接对象Connection是从连接池中获取的,那么调用connection.close()方法,则不会再关闭连接了。而是归还链接。
2、一般我们不去实现它,由数据库厂商来实现
1、C3P0:数据库连接池技术
2、Druid:数据库连接池实现技术,有阿里巴巴提供的
D、C3P0数据库连接池技术
步骤:
1、导入jar包:c3p0-0.9.5.5.jar mchange-commons-java-0.2.19.jar 和数据库的驱动架包
2、定义配置文件:
名称:c3p0.properties.xml 或者 c3p0-config.xml
路径:直接将配置文件放在src目录下即可
3、创建核心对象 数据库连接池对象 ComboPooledDataSource
4、获取连接:getConnection
c3p0-config.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<!-- 数据库驱动名 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- 数据库的url -->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db2</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<!--初始化时申请获取5个连接,取值应在minPoolSize与maxPoolSize之间。-->
<property name="initialPoolSize">5</property>
<!-- 连接池里允许申请的最大的连接数量 -->
<property name="maxPoolSize">10</property>
<!-- 最小的连接数量 -->
<property name="minPoolSize">4</property>
<!--超时时间 (等待3秒才会报错)-->
<property name="checkoutTimeout">3000</property>
</default-config>
<named-config name="c3p0mysql">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db2</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">4</property>
<property name="maxPoolSize">8</property>
<!-- 最小的连接数量 -->
<property name="minPoolSize">3</property>
<!--超时时间-->
<property name="checkoutTimeout">1000</property>
</named-config>
<named-config name="c3p0oracle">
<property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
<property name="jdbcUrl">jdbc:oracle:thin:@地址:端口:ORCL</property>
<property name="user">root</property>
<property name="password">root</property>
<!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。-->
<property name="initialPoolSize">3</property>
<!--连接池中保留的最大连接数。-->
<property name="maxPoolSize">6</property>
<!--连接池中保留的最小连接数 -->
<property name="minPoolSize">2</property>
<!--超时时间-->
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
public class C3p0Demo01 {
public static void main(String[] args) {
//1创建数据库连接池对象
//DataSource dataSource = new ComboPooledDataSource();//默认<default-config>
DataSource dataSource = new ComboPooledDataSource("c3p0mysql");//使用指定的配置
//2获取连接对象
try {
Connection connection = dataSource.getConnection();
//3打印
System.out.println(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public class C3p0Demo02 {
public static void main(String[] args) throws SQLException {
//1创建数据库连接对象
DataSource dataSource = new ComboPooledDataSource();//使用默认<default-config>
//2获取连接
for (int i = 1; i <= 11; i++) {
Connection connection = dataSource.getConnection();
System.out.println(i+":"+connection);
if (i==5){
connection.close();//归还连接到连接池
}
}
}
}
E、Druid:数据库连接池实现技术,有阿里巴巴提供的
1步骤:
1、导入jar包:druid-1.1.21.jar 和数据库的驱动架包
2、定义配置文件:
是properties形式的
可以是任意名称,可以放在任意目录下
3、创建核心对象 数据库连接池对象 DruidDataSourceFactory
4、获取连接:getConnection
2定义工具类
1定义一个JDBCUtils
2提供静态代码块加载配置文件,初始化连接池对象
3提供方法
1获取连接方法:通过数据库连接池获取连接
2释放资源
3获取连接池的方法
JDBCUtils工具类
public class JdbcUtils {
//1定义成员变量
private static DataSource dataSource;
static {
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
try {
Properties properties = new Properties();
properties.load(inputStream);
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnetion() throws SQLException {
return dataSource.getConnection();
}
public static void close(Statement statement,Connection connection){
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection !=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet resultSet, Statement statement, Connection connection){
if (resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection !=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static DataSource getDataSource(){
return dataSource;
}
}
druid.properties文件的配置
# druid.properties文件的配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db2
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大超时时间
maxWait=3000
小练习
public class DruidDemo02 {
public static void main(String[] args) {
Connection connetion = null;
PreparedStatement statement = null;
try {
connetion = JdbcUtils.getConnetion();
connetion.setAutoCommit(false);
String sql = "insert into person values(null,?,?)";
statement = connetion.prepareStatement(sql);
statement.setString(1,"李毅");
statement.setInt(2,26);
int count = statement.executeUpdate();
System.out.println(count);
connetion.commit();
connetion.close();
} catch (SQLException e) {
try {
connetion.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.close(statement,connetion);
}
}
}
6、Spring JDBC
Spring 框架对jdbc的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
步骤:
1、导入架包
2、创建JDBCTemplate对象。依赖于数据源DataSource
JdbcTemplate template = new JdbcTemplate(ds);
3、调用JdbcTemplate的方法来完成CRUD的操作
update():执行DML语句。增删改语句。
queryForMap():查询结果将结果集封装为map集合 //注意这个方法的查询结果集长度只能是1
queryForList():查询结果将结果集封装为list集合
query():查询结果,将结果封装为JavaBean对象//查询返回对象类型的集合
new BeanPropertyRowMapper<类型>(类型.class)
queryForObject():查询结果,将结果封装为对象//一般用来查询聚合函数的
public class JdbcTemplateDemo01 {
public static void main(String[] args) {
//1导jar包
//2创建JdbcTemplate对象
JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
//3调用方法
String sql = "insert into person values(?,?,?)";
int count = template.update(sql, null, "千年老妖", 1000);
System.out.println(count);
}
}
public class JdbcTemplateDemo02 {
private JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
@Test
public void test1(){
Person person = new Person();
ArrayList<Person> list = new ArrayList<>();
String sql = "update person set age = ? where id = ?";
int update = template.update(sql, 26, 1);
System.out.println(update);
}
@Test
public void test2(){
String sql = "insert into person values (?,?,?)";
int update = template.update(sql, null,"刘飞",28);
System.out.println(update);
}
@Test
public void test3(){
String sql = "delete from person where id = ?";
int update = template.update(sql,4);
System.out.println(update);
}
@Test
public void test4(){
String sql = "select * from person where id = ?";
//注意这个方法的查询结果集长度只能是1
Map<String, Object> stringObjectMap = template.queryForMap(sql, 1);
Set<Map.Entry<String, Object>> entrySet = stringObjectMap.entrySet();
/*for (Map.Entry<String, Object> entry : entrySet) {
System.out.println(entry.getKey()+entry.getValue());
}*/
Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
while (iterator.hasNext()){
Map.Entry<String, Object> entry = iterator.next();
System.out.println(entry.getKey()+entry.getValue());
}
}
@Test
public void test5(){
String sql = "select * from person where id = ? or id = ?";
List<Map<String, Object>> maps = template.queryForList(sql,1,2);
//System.out.println(maps);
for (Map<String, Object> map : maps) {
System.out.println(map);
}
}
@Test
public void test6(){
String sql = "select * from person where id = ? or id = ?";
/*List<Person> list = template.query(sql, new RowMapper<Person>() {
@Override
public Person mapRow(ResultSet resultSet, int i) throws SQLException {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
Person person = new Person(id,name,age);
return person;
}
},1,3);
for (Person person : list) {
System.out.println(person);
}*/
List<Person> list = template.query(sql, new BeanPropertyRowMapper<Person>(Person.class), 1, 3);
System.out.println(list);
}
@Test
public void test7(){
String sql = "select count(1) from person where id = ? or id = ?";
Integer integer = template.queryForObject(sql, Integer.class,1,5);
System.out.println(integer);
}
}