通过Java代码操作数据库。
IDEA IntelliJ IDEA是一种商业化销售的Java集成开发环境(Integrated Development Environment,IDE)工具软件。
常用快捷键
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 运行 Alt+Shift+F10 调试 Shift+F9 停止 Ctrl+F2 #编写代码 复制当前行 Ctrl+D 删除当前行 Ctrl+Y 移动代码(块 Ctrl+Shift+↑/↓ 代码重构 Ctrl+Shift+Alt+T 格式化代码 Ctrl+Alt+L 包裹代码(if /else 、try /catch ...) Ctrl+Alt+T 提取变量 Ctrl+Alt+V #代码生成 for 循环 fori+Tabprintln sout+Tab main psvm+Tab 查询模板 Ctrl+J 构造函数、toString、getter/setter、重写父类方法 Alt+Insert user .for +Tab => for (User user:users) user.getNum() .var +Tab => Date birthday = user.getNum() #编辑 重命名 Shift+F6 以单词为单位前后移动 Ctrl+←/→ 以代码块为单位前后移动 Ctrl+/和Ctrl+Shift+/ 定位到错误处 F2和Shift+F2 #智能提示 基本提示 Ctrl+Space 按类型信息提示 Ctrl+Shift+Space 快速修复 Alt+Enter 自动补全末尾 Ctrl+Shift+Enter #窗口切换 Project Alt+1 Editor Esc #查找 打开类、文件 Ctrl+N和Ctrl+Shift+N 全局搜索 Shift+Shift 打开当前类的继承关系 Ctrl+H
Properties类 概述 Properties
类继承于Hashtable
,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。可以使用Properties
类从文件中动态加载配置 。
构造方法 1 public Properties():创建一个空的属性列表
成员方法 1 2 3 4 public Object setProperty (String key, String value) :保存一对属性public String getProperty (String key) :使用此属性列表中指定的键搜索属性值public Set<String> stringPropertyNames () :所有键的名称的集合public void load (InputStream inStream) :从字节输入流中读取键值对
基本的存储方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class PropertiesDemo { public static void main (String[] args) throws IOException { Properties properties = new Properties(); properties.setProperty("filename" , "a.txt" ); properties.setProperty("length" , "209385038" ); properties.setProperty("location" , "D:\\a.txt" ); System.out.println(properties); System.out.println(properties.getProperty("filename" )); System.out.println(properties.getProperty("length" )); System.out.println(properties.getProperty("location" )); } } {filename=abc.txt, length=89757 , location=D:\a.txt} abc.txt 89757 D:\a.txt
与流相关的方法
从字节输入流中读取键值对。
1 2 3 4 filename=a .txt length=209385038 location=D:\a .txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class PropertiesDemo { public static void main (String[] args) throws IOException { Properties properties = new Properties(); properties.load(new FileInputStream("E:\\workspace\\IDEA\\MySQL\\abc.txt" )); Set<String> list = properties.stringPropertyNames(); for (String key : list) { System.out.println(key + " " + properties.getProperty(key)); } } } filename a.txt length 209385038 location D:a.txt
JDBC 概述
JDBC(Java DataBase Connectivity)
是一种用于执行SQL语句的Java API,是Java访问数据库的标准规范,由一组用Java语言编写的接口和类组成,可以为不同的关系型数据库提供统一访问。
驱动
是JDBC接口的实现,一般由数据库厂商提供,驱动实现不同设备之间进行通信。
JDBC规范(四个核心对象)
DriverManager:用于注册驱动
Connection: 表示与数据库创建的连接
Statement: 操作数据库sql语句的对象
ResultSet: 结果集(一张虚拟表)
JDBC连接数据库
开发步骤
导入mysql-connector-java-5.1.37-bin.jar包
注册驱动
获取连接对象
创建SQL语句
获取Statement对象来执行SQL语句
执行SQL语句,返回影响的行数或结果集
打印返回值或遍历打印结果集中的数据
关闭资源
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public class JDBCDemo { public static void main (String[] args) throws SQLException { try { Class.forName("com.mysql.jdbc.Driver" ); } catch (ClassNotFoundException e) { e.printStackTrace(); } Connection connection = DriverManager.getConnection("jdbc:mysql:///product" , "root" , "root" ); String sql = "select * from product" ; Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(sql); while (rs.next()) { String pid = rs.getString("pid" ); String pname = rs.getString("pname" ); double price = rs.getDouble("price" ); String category_id = rs.getString("category_id" ); System.out.println(pid + "," + pname + "," + price + "," + category_id); } rs.close(); statement.close(); connection.close(); } }
编写JDBC工具类 “获得数据库连接”操作,将在以后的增删改查所有功能中都存在,可以封装成JDBCUtils
工具类,实现代码复用。
JDBCUtils
工具类实现的功能
通过DataBase.conf
文件配置连接
获取连接对象
关闭资源
配置文件中的内容
1 2 3 url =jdbc:mysql:///productusername =rootpassword =root
JDBC工具类中的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public class JDBCUtils { private static String url; private static String username; private static String password; private JDBCUtils () { } static { try { Class.forName("com.mysql.jdbc.Driver" ); } catch (ClassNotFoundException e) { e.printStackTrace(); } try { Properties properties = new Properties(); FileInputStream fis = new FileInputStream("DataBase.conf" ); properties.load(fis); url = properties.get("url" ).toString(); username = properties.get("username" ).toString(); password = properties.get("password" ).toString(); fis.close(); } catch (IOException e) { e.printStackTrace(); } } public static Connection getConnection () throws SQLException { Connection connection = DriverManager.getConnection(url, username, password); return connection; } public static void closeResource (Connection con, Statement st) throws SQLException { st.close(); con.close(); } public static void closeResource (Connection con, Statement st, ResultSet rs) throws SQLException { rs.close(); st.close(); con.close(); } }
PreparedStatement接口 SQL注入问题 用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的含义。
SQL注入案例
有登录案例SQL语句如下:
1 SELECT * FROM 用户表 WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;
当用户输入正确的账号与密码后,查询到了信息则让用户登录。但当用户输入的密码内容为'XXX' OR 'a'='a'
时,真正执行的代码变为:
1 SELECT * FROM 用户表 WHERE NAME = 'XXX' AND PASSWORD = 'XXX' OR 'a' = 'a' ;
上述查询语句是永远可以查询出结果的,这便是SQL注入问题。为此,我们使用PreparedStatement
来解决对应的问题。
概述 PreparedStatement
接口表示预编译的 SQL 语句的对象,SQL 语句被预编译并存储在 PreparedStatement 对象中,然后可以使用此对象多次高效地执行该语句。
获取对象 通过调用Connection
接口的prepareStatement(String sql)
方法返回PreparedStatement
对象。
成员方法 1 2 3 int executeUpdate () :执行增删改,返回影响数据的行数ResultSet executeQuery () :执行 SQL 查询,并返回该查询生成的 ResultSet 结果集对象 boolean execute () :执行任何种类的 SQL 语句,一般不用
特点
性能高
预编译sql语句
能过滤掉用户输入的关键字
使用步骤
获取连接对象
创建sql语句,使用占位符?替换要传入的实际参数
获取预编译语句执行对象
设置实际参数
执行SQL语句
打印数据
关闭资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class PreparedStatementDemo { public static void main (String[] args) throws SQLException { Connection con = JDBCUtils.getConnection(); String sql = "select * from account where name = ? and password = ?" ; PreparedStatement psm = con.prepareStatement(sql); psm.setString(1 , "jack" ); psm.setString(2 , "123456" ); ResultSet rs = psm.executeQuery(); if (rs.next()) { int id = rs.getInt("id" ); String name = rs.getString("name" ); double money = rs.getDouble("money" ); String password = rs.getString("password" ); System.out.println(id + "," + name + "," + money + "," + password); } JDBCUtils.closeResource(con, psm); } }
c3p0连接池 数据库连接池概述 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。
连接池可以理解为存放多个连接的集合,使用连接池技术可以节省 建立数据库连接耗费的资源和时间 ,提高性能 。
常见的连接池:C3P0、DRUID。
DataSource
接口Java为数据库连接池提供了公共的接口:javax.sql.DataSource
,各个厂商需要让自己的连接池实现这个接口。
编写c3p0连接池工具类 c3p0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
c3p0连接池工具类实现的功能
创建连接池对象,通过src
目录下的c3p0-config.xml
文件配置连接
从池中获得一个连接
关闭资源
配置文件中的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <c3p0-config > <default-config > <property name ="driverClass" > com.mysql.jdbc.Driver</property > <property name ="jdbcUrl" > jdbc:mysql://localhost:3306/day03</property > <property name ="user" > root</property > <property name ="password" > root</property > <property name ="initialPoolSize" > 5</property > <property name ="maxPoolSize" > 10</property > <property name ="checkoutTimeout" > 2000</property > <property name ="maxIdleTime" > 1000</property > </default-config > </c3p0-config >
c3p0连接池常用的配置参数:
参数
说明
initialPoolSize
初始连接数
maxPoolSize
最大连接数
checkoutTimeout
最大等待时间
maxIdleTime
最大空闲回收时间
c3p0连接池工具类中的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class C3P0Utils { private C3P0Utils () { } private static DataSource ds = new ComboPooledDataSource (); public static DataSource getDataSource () { return ds; } public static Connection getConnection () throws SQLException { return ds.getConnection (); } public static void closeReference (Connection con, Statement sm, ResultSet rs) { try { rs.close (); } catch (SQLException e) { e.printStackTrace (); } try { sm.close (); } catch (SQLException e) { e.printStackTrace (); } try { con.close (); } catch (SQLException e) { e.printStackTrace (); } } public static void closeReference (Connection con, Statement sm) { try { sm.close (); } catch (SQLException e) { e.printStackTrace (); } try { con.close (); } catch (SQLException e) { e.printStackTrace (); } } }
使用c3p0连接池工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 public class C3P0UtilsDemo { @Test public void insert () throws SQLException { Connection con = C3P0Utils.getConnection(); String sql="insert into product (pid,pname,price,category_id) values(?,?,?,?)" ; PreparedStatement psm=con.prepareStatement(sql); psm.setString(1 ,"p011" ); psm.setString(2 ,"粗粮" ); psm.setDouble(3 ,999 ); psm.setString(4 ,"c004" ); int count=psm.executeUpdate(); System.out.println("影响了" +count+"条数据" ); C3P0Utils.closeReference(con,psm); } @Test public void delete () throws SQLException { Connection con = C3P0Utils.getConnection(); String sql="delete from product where pname=?" ; PreparedStatement psm=con.prepareStatement(sql); psm.setString(1 ,"水果" ); int count=psm.executeUpdate(); System.out.println("影响了" +count+"条数据" ); C3P0Utils.closeReference(con,psm); } @Test public void query () throws SQLException { Connection con = C3P0Utils.getConnection(); String sql="select * from product where pname=?" ; PreparedStatement psm=con.prepareStatement(sql); psm.setString(1 ,"联想" ); ResultSet rs=psm.executeQuery(); while (rs.next()){ int pid = rs.getInt("pid" ); String pname = rs.getString("pname" ); double price = rs.getDouble("price" ); String category_id = rs.getString("category_id" ); System.out.println(pid+" " +pname+" " +price+" " +category_id); } C3P0Utils.closeReference(con,psm,rs); } @Test public void update () throws SQLException { Connection con = C3P0Utils.getConnection(); String sql="update product set price=? where pname=?" ; PreparedStatement psm=con.prepareStatement(sql); psm.setDouble(1 ,5000 ); psm.setString(2 ,"联想" ); int count=psm.executeUpdate(); System.out.println("影响了" +count+"条数据" ); C3P0Utils.closeReference(con,psm); } }
DBUtils 为了简化JDBC开发,我们采用Apache Commons
组件的一个成员:DBUtils
。
DBUtils
是JDBC的简化开发工具包,需要项目导入commons-dbutils-1.6.jar
才能使用。
概述 DBUtils
是java编程中的数据库操作实用工具,小巧简单实用。DBUtils
封装了对JDBC的操作,简化了JDBC操作,可以少写代码。
Dbutils
的三个核心功能
QueryRunner
类:提供对sql语句操作的API
ResultSetHandler
接口:用于定义select操作后,怎样封装结果集
DbUtils
类:它是一个工具类,定义了关闭资源与事务处理的方法
QueryRunner 构造方法 1 2 QueryRunner(DataSource):创建核心类,【提供】数据源,内部自己维护Connection QueryRunner () :创建核心类,【不提供】数据源,在进行具体操作时,【需要】提供Connection
成员方法 1 2 3 4 update (String sql, Object ... params ) :执行DML语句,【不使用】Connectionupdate (Connection con, String sql, Object ... params ) :【使用】提供的Connection,完成DML语句query (String sql, ResultSetHandler, Object ... params ) :执行DQL语句,并将查询结果封装到对象中query (Connection con, String sql, ResultSetHandler, Object ... params ) :使用提供的Connection,执行DQL语句,并将查询结果封装到对象中
实现增删改 update(String sql, Object... params)
:用来完成表数据的增加、删除、更新操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class DBUtilsDemo { @Test public void insert () throws SQLException { QueryRunner qr=new QueryRunner(C3P0Utils.getDataSource()); int count=qr.update("insert into product (pname,price,category_id) values(?,?,?)" ,"思念水饺" ,23 ,"f001" ); System.out.println("影响了" +count+"条数据" ); } @Test public void delete () throws SQLException { QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); Object[] params={"思念水饺" }; int count=qr.update("delete from product where pname=?" ,params); System.out.println("影响了" +count+"条数据" ); } @Test public void update () throws SQLException { QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); Object[] params={4000 ,"联想" }; int count = qr.update("update product set price=? where pname=?" , params); System.out.println("影响了" +count+"条数据" ); } }
实现查询 query(String sql, ResultSetHandler<T> rsh, Object... params)
:用来完成表数据的查询操作
ResultSetHandler结果集
BeanHandler
:将结果集中第一条记录封装到一个指定的javaBean中。
BeanListHandler
:将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
ScalarHandler
:它是用于单数据。例如select count(*) from
表操作。
ColumnListHandler
:将结果集中指定字段的值,封装到一个List集合中
JavaBean
JavaBean
就是一种(遵循一定规范的)类,在开发中常用于封装数据。具有如下特性:
需要实现接口:java.io.Serializable
,通常可以省略这个步骤
提供私有字段:private 类型 字段名;
提供getter/setter
方法
提供无参构造
POJO
POJO
翻译为中文就是普通Java类
,具有一部分JavaBean
规范的类就可以称为POJO
类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class DBUtilsDemo { @Test public void queryProduct () throws SQLException { QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); Product product = qr.query("select * from product where pname=?" , new BeanHandler<>(Product.class), "联想" ); System.out.println(product); } @Test public void queryList () throws SQLException { QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); List<Product> list = qr.query("select * from product" , new BeanListHandler<>(Product.class)); for (Product product : list) { System.out.println(product.getPid()+" " +product.getPname()+" " +product.getPrice()+" " +product.getCategory_id()); } } @Test public void queryColumn () throws SQLException { QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); List<Object> list = qr.query("select pname from product" , new ColumnListHandler()); for (Object pname : list) { System.out.println(pname); } } @Test public void queryCount () throws SQLException { QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); Long count = (Long)qr.query("select count(*) from product" , new ScalarHandler()); System.out.println("查询到了" +count+"条结果" ); } }
事务操作 概述 事务主要用于处理操作量大,复杂度高的数据。
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
事务用来管理 insert,update,delete 语句
事务特性:ACID 一般来说,事务是必须满足4个条件(ACID):原子性(A tomicity,或称不可分割性)、一致性(C onsistency)、隔离性(I solation,又称独立性)、持久性(D urability)。
原子性: 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性: 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性: 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性: 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
并发访问问题 如果不考虑隔离性,事务存在三种并发访问问题:
脏读:一个事务读到了另一个事务未提交的数据
不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发另一个事务,在事务中的多次查询结果不一致
虚读 /幻读:一个事务读到了另一个事务已经提交(insert)的数据。导致另一个事务,在事务中多次查询的结果不一致
隔离级别:解决问题 数据库规范规定了4种隔离级别,分别用于描述两个事务并发的所有情况。
read uncommitted:读未提交,一个事务读到另一个事务没有提交的数据。
存在:3个问题(脏读、不可重复读、虚读)
解决:0个问题
read committed 读已提交,一个事务读到另一个事务已经提交的数据。
存在:2个问题(不可重复读、虚读)
解决:1个问题(脏读)
repeatable read:可重复读,在一个事务中读到的数据始终保持一致,无论另一个事务是否提交。
存在:1个问题(虚读)
解决:2个问题(脏读、不可重复读)
serializable 串行化,同时只能执行一个事务,相当于事务中的单线程。
存在:0个问题。
解决:3个问题(脏读、不可重复读、虚读)
安全和性能对比
安全性:serializable
> repeatable read
> read committed
> read uncommitted
性能 : serializable
< repeatable read
< read committed
< read uncommitted
常见数据库的默认隔离级别
MySql:repeatable read
Oracle:read committed
查看MySQL的事务隔离级别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mysql> select @@tx _isolation; + | @@tx _isolation | + | REPEATABLE- READ | + mysql> select @@global .tx_isolation; + | @@global .tx_isolation | + | REPEATABLE- READ | + mysql> set session transaction isolatin level repeatable read; mysql> set global transaction isolation level repeatable read;
MySQL事务操作
SQL语句
描述
begin 或 start transaction
开启事务
commit
提交事务
rollback
回滚事务
MySQL中有两种方式可以进行事务的管理
自动提交:执行一条 SQL 语句便提交一次事务,MySQL 默认开启。
手动提交:–先显式开启事务,再执行SQL语句,最后提交或回滚。
1 2 3 4 5 6 7 8 9 10 11 mysql> show variables like 'autocommit' ; + | Variable_name | Value | + | autocommit | ON | + SET AUTOCOMMIT= 0 ; SET AUTOCOMMIT= 1 ;
1 2 3 4 5 6 7 begin ;update account set money= money-1000 where name= 'jack' ; update account set money= money+ 1000 where name= 'rose' ; commit ;rollback ;
JDBC事务操作
Connection 对象的方法名
描述
conn.setAutoCommit(false)
开启事务
conn.commit()
提交事务
conn.rollback()
回滚事务
DBUtils事务操作
Connection对象的方法名
描述
conn.setAutoCommit(false)
开启事务
new QueryRunner()
创建核心类,不设置数据源(手动管理连接)
query(conn , sql , handler, params ) 或 update(conn, sql , params)
手动传递连接, 执行SQL语句CRUD
DbUtils.commitAndCloseQuietly(conn)
提交并关闭连接,不抛异常
DbUtils.rollbackAndCloseQuietly(conn)
回滚并关闭连接,不抛异常
事务总结 事务特性:ACID
原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
一致性(Consistency)事务前后数据的完整性必须保持一致
隔离性(Isolation)事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离
持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
案例:三层架构
开发中,常使用分层思想
不同的层次结构分配不同的解决过程,各个层次间组成严密的封闭系统
不同层级结构彼此平等
分层的目的
不同层次,使用不同的包表示
持久层:moe.sannaha.dao
业务逻辑层:moe.sannaha.service
表示层:moe.sannaha.web
其他包
javabean:moe.sannaha.domain
工具:moe.sannaha.utils
配置文件 src/c3p0-config.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <c3p0-config > <default-config > <property name ="driverClass" > com.mysql.jdbc.Driver</property > <property name ="jdbcUrl" > jdbc:mysql://localhost:3306/bank</property > <property name ="user" > root</property > <property name ="password" > root</property > <property name ="initialPoolSize" > 5</property > <property name ="maxPoolSize" > 10</property > <property name ="checkoutTimeout" > 2000</property > <property name ="maxIdleTime" > 1000</property > </default-config > </c3p0-config >
c3p0连接池工具类 src/moe.sannaha.utils/C3P0Utils.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package moe.sannaha.utils;import com.mchange.v2.c3p0.ComboPooledDataSource;import javax.sql.DataSource;import java.sql.Connection;import java.sql.SQLException;public class C3P0Utils { private static DataSource ds=new ComboPooledDataSource(); public static DataSource getDataSource () { return ds; } public static Connection getConnection () throws SQLException { return ds.getConnection(); } }
pojo类 src/moe.sannaha.pojo/Account.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 package moe.sannaha.pojo;import java.util.Objects;public class Account { private int id; private String name; private double money; private String password; @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Account account = (Account) o; return name.equals(account.name) && password.equals(account.password); } @Override public int hashCode () { return Objects.hash(name, password); } @Override public String toString () { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + ", password='" + password + '\'' + '}' ; } public int getId () { return id; } public void setId (int id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public double getMoney () { return money; } public void setMoney (double money) { this .money = money; } public String getPassword () { return password; } public void setPassword (String password) { this .password = password; } public Account (int id, String name, double money, String password) { this .id = id; this .name = name; this .money = money; this .password = password; } public Account () { } }
持久层 src/moe.sannaha.dao/AccountDao.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package moe.sannaha.dao;import moe.sannaha.utils.C3P0Utils;import org.apache.commons.dbutils.QueryRunner;import java.sql.Connection;import java.sql.SQLException;public class AccountDao { public void moneyCome (Connection con,String name,double money) throws SQLException { QueryRunner qr = new QueryRunner(); qr.update(con,"update account set money=money+? where name=?" ,money,name); } public void moneyGo (Connection con,String name,double money) throws SQLException { QueryRunner qr = new QueryRunner(); qr.update(con,"update account set money=money-? where name=?" ,money,name); } }
src/moe.sannaha.dao/LoginDao.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package moe.sannaha.dao;import moe.sannaha.pojo.Account;import moe.sannaha.utils.C3P0Utils;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanHandler;import java.sql.SQLException;public class LoginDao { public Account login (String name, String password) throws SQLException { QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); Account account = qr.query("select * from account where name=? and password=?" , new BeanHandler<Account>(Account.class), name, password); return account; }
业务逻辑层 src/moe.sannaha.service/AccountService.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package moe.sannaha.service;import moe.sannaha.dao.AccountDao;import moe.sannaha.utils.C3P0Utils;import org.apache.commons.dbutils.DbUtils;import java.sql.Connection;import java.sql.SQLException;public class AccountService { public void transfer (String nameCome,String nameGo,double money) throws SQLException { AccountDao ad = new AccountDao(); Connection con = C3P0Utils.getConnection(); con.setAutoCommit(false ); try { ad.moneyGo(con,nameGo,money); ad.moneyCome(con,nameCome,money); DbUtils.commitAndCloseQuietly(con); System.out.println("转账成功!" ); } catch (Exception e) { DbUtils.rollbackAndCloseQuietly(con); System.out.println("转账失败!" ); e.printStackTrace(); } }
src/moe.sannaha.service/LoginService.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package moe.sannaha.service;import moe.sannaha.dao.LoginDao;import moe.sannaha.pojo.Account;import java.sql.SQLException;public class LoginService { public boolean loginService (String name, String password) throws SQLException { LoginDao loginDao = new LoginDao(); Account account=loginDao.login(name,password); if (account==null ){ System.out.println("登录失败,请重新登录!" ); return false ; }else { System.out.println("登录成功" ); System.out.println("欢迎您," +account.getName()); System.out.println("您的账户余额为:" +account.getMoney()); return true ; } } }
表示层 src/moe.sannaha.app/AccountApp.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package moe.sannaha.app;import moe.sannaha.service.AccountService;import moe.sannaha.service.LoginService;import java.sql.SQLException;import java.util.Scanner;public class AccountApp { public static void main (String[] args) throws SQLException { while (true ) { Scanner sc = new Scanner(System.in); System.out.println("登录程序执行\n请输入用户名:" ); String name=sc.nextLine(); System.out.println("请输入6位数字密码:" ); String password=sc.nextLine(); LoginService ls = new LoginService(); if (ls.loginService(name,password)){ AccountService as = new AccountService(); System.out.println("转账程序执行\n请输入要转到的账户名:" ); String nameCome=sc.nextLine(); System.out.println("请输入要转出的金额:" ); Double money=Double.parseDouble(sc.nextLine()); as.transfer(nameCome,name,money); break ; } } } }