JDBC - Java连接数据库
一、概述
二、JDBC快速入门
三、JDBC API 详解
DriverManage (驱动管理类)
- 设置时区和编码参数时,连接多个参数用的是 & 。
Connection(获取执行对象)
Statement(SQL执行对象)
ResultSet(结果集对象)
public static void main(String[] args) throws Exception { //自动注册驱动 //获取连接对象 String url = "jdbc:mysql:///day16useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8"; String username = "*******"; String password = "********"; Connection conn = DriverManager.getConnection(url, username, password); //定义sql语句 String sql = "select * from account"; //获取执行对象 Statement stmt = conn.createStatement(); //执行sql语句,获取结果 ResultSet rs = stmt.executeQuery(sql); //处理结果 //创建集合,存储所有的用户对象 ArrayList<Account> accounts = new ArrayList<>(); while (rs.next()) { //获取数据 int id = rs.getInt("id"); String name = rs.getString("name"); double money = rs.getDouble("money"); //创建用户对象 //Account account = new Account(id,name,money); Account account = new Account(); account.setId(id); account.setName(name); account.setMoney(money); //添加对象到集合中 accounts.add(account); } System.out.println(accounts); //关闭资源 stmt.close(); conn.close(); }
Connection(管理事务)
public static void main(String[] args) throws Exception { //注册驱动-自动注册 //获取连接对象 String url = "jdbc:mysql:///day16?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8"; String username = "*****"; String password = "********"; Connection conn = DriverManager.getConnection(url, username, password); //定义sql语句 //张三转出500 String sql = "UPDATE account SET money = 500 WHERE id=1"; //李四转入500 String sql2 = "UPDATE account SET money = 1500 WHERE id=2"; //获取执行sql的对象 Statement stmt = conn.createStatement(); //张三个李四转账的两个操作,需要要么都执行,要么都不执行。 try { //开启事务 conn.setAutoCommit(false); //执行sql,获取结果 int count = stmt.executeUpdate(sql); //异常代码 //System.out.println(1/0); int count2 = stmt.executeUpdate(sql2); //处理结果 System.out.println(count); System.out.println(count2); //执行完成,提交事务 conn.commit(); }catch (Exception e){ //出了问题,回滚 conn.rollback(); } //关闭资源 stmt.close(); conn.close(); }
SQL注入
SQL注入实现的原理 - 通过引号拼接,让 or 成为关键字,后面‘1’=‘1‘ 一直为true,欺骗编译器,让我通过检验,也就成功进入了界面,看到了保密信息。
PreparedStatement(预编译sql执行对象)
- 想把字符串中的内容改成变量:直接选中内容,加上一对双引号,在引号里面加两个 + 号,加号中间写变量
- 解决SQL注入 - 预编译,他会转义特殊字符
public static void main(String[] args) throws Exception { //需求:根据用户输入的用户名和密码判断是否登录成功 //注册驱动-自动 //获取连接对象 String url = "jdbc:mysql:///test?useServerPrepStmts=true&useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8"; String username = "*****"; String password = "********"; Connection conn = DriverManager.getConnection(url, username, password); //输入用户名和密码 String uname = "lisi"; String pwd = "'or'1'='1"; //定义sql语句 String sql = "select * from user where username=? and password=?"; //获取预编译执行对象 PreparedStatement pstmt = conn.prepareStatement(sql); //pstmt.setXxx(?的位置,替换?的数据); Xxx:?的数据类型 pstmt.setString(1, uname); pstmt.setString(2, pwd); //执行sql,获取结果 //获取预编译执行对象,就传入了sql,所以这里不用再传入sql语句了 ResultSet resultSet = pstmt.executeQuery(); //判断是否有结果(有结果,登录成功;没有结果,登录失败) //resultSet.next() 如果是true 代表有结果,如果是false代表没有结果 if (resultSet.next()) { System.out.println("恭喜,登录成功"); } else { System.out.println("登录失败"); } }
四、数据库连接池
概述
原理
c3p0连接池使用步骤
- 硬编码 - 在代码里写死了
- 软编码 - 运行时从文件中找
c3p0 配置文件
<1> c3p0.properties
c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql://localhost:3306/day16?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8 c3p0.user=**** c3p0.password=******** c3p0.initialPoolSize=5 c3p0.maxPoolSize=20
<2> c3p0-config.xml
<c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/day16?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8</property> <property name="user">*****</property> <property name="password">********</property> <property name="initialPoolSize">5</property> <property name="maxPoolSize">21</property> </default-config> </c3p0-config>
public static void main(String[] args) throws Exception { //导入 jar 包。 //导入配置文件到src目录下。 //创建 C3P0 连接池对象。 ComboPooledDataSource pool = new ComboPooledDataSource(); //获取数据库连接进行使用。 Connection conn = pool.getConnection(); //sql语句 String sql = "insert into account values(null,'zl',1000)"; //获取执行对象 Statement stmt = conn.createStatement(); //执行sql int count = stmt.executeUpdate(sql); //处理结果 System.out.println("count:" + count); System.out.println("使用中的连接池数量:"+pool.getNumBusyConnections()); System.out.println("空闲中的连接池数量:"+pool.getNumIdleConnections()); System.out.println("空闲中的连接池数量:"+pool.getMaxPoolSize()); //关闭连接对象 conn.close(); //等一会,让其归还 Thread.sleep(1000); System.out.println("使用中的连接池数量:"+pool.getNumBusyConnections()); System.out.println("空闲中的连接池数量:"+pool.getNumIdleConnections()); System.out.println("空闲中的连接池数量:"+pool.getMaxPoolSize()); }
Druid连接池使用步骤
硬编码
软编码
druid配置文件 - druid.properties
# 数据库连接参数 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/day16?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8 username=**** password=******** # 连接池的参数 initialSize=5 maxActive=20
public static void main(String[] args) throws Exception {
//导入 jar 包。
//编写配置文件,放在 src 目录下。
//通过 Properties 对象加载配置文件。
Properties p = new Properties();
InputStream in = new FileInputStream("day16\\src\\driud.properties");
p.load(in);
//通过 Druid 连接池工厂类静态方法获取数据库连接池对象。
//DruidDataSourceFactory.createDataSource(Properties p)
//DataSource没有Druid连接池中的相关功能,实际上返回了DataSource实现类对象 DruidDataSource
//DataSource pool = DruidDataSourceFactory.createDataSource(p);
DruidDataSource pool = (DruidDataSource) DruidDataSourceFactory.createDataSource(p);
//获取数据库连接进行使用。
DruidPooledConnection conn = pool.getConnection();
//定义sql语句
String sql = "insert into account values(null,'sq',2000)";
//获取sql执行对象
Statement stmt = conn.createStatement();
//执行sql语句,获取结果
int count = stmt.executeUpdate(sql);
//处理结果
System.out.println("count:"+count);
System.out.println("使用中的连接池数量:"+pool.getActiveCount());
System.out.println("空闲中的连接池数量:"+pool.getPoolingCount());
System.out.println("空闲中的连接池数量:"+pool.getMaxActive());
//关闭资源
stmt.close();
conn.close();
//等一会,让其归还
Thread.sleep(1000);
System.out.println("使用中的连接池数量:"+pool.getActiveCount());
System.out.println("空闲中的连接池数量:"+pool.getPoolingCount());
System.out.println("空闲中的连接池数量:"+pool.getMaxActive());
}