一.Hello JDBC
1.通过Class.forName("com.mysql.jdbc.Driver");
初始化驱动类com.mysql.jdbc.Driver
Class.forName是把这个类加载到JVM中
加载的时候,就会执行其中的静态初始化块,完成驱动的初始化的相关工作。
2.
Connection c = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:port/databaseName?
characterEncoding=UTF-8",user,password);
3.
// 注意:使用的是 java.sql.Statement
// 不要不小心使用到: com.mysql.jdbc.Statement;
Statement s = c.createStatement();
4.
// 准备sql语句
// 注意: 字符串要用单引号'
String sql = "insert into hero values(null,"+"'提莫'"+","+313.0f+","+50+")";
s.execute(sql);
5.
先关闭Statement后关闭Connection
可以在finally中关闭也可使用try-with-resource的方式自动关闭连接
finally {
// 数据库的连接时有限资源,相关操作结束后,养成关闭数据库的好习惯
// 先关闭Statement
if (s != null)
try {
s.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 后关闭Connection
if (c != null)
try {
c.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
因为Connection和Statement都实现了AutoCloseable接口
try (
Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
"root", "admin");
Statement s = c.createStatement();
)
{
String sql = "insert into hero values(null," + "'提莫'" + "," + 313.0f + "," + 50 + ")";
s.execute(sql);
//增删改都是用这种方法,查询请看下一小节
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
6.PreparedStatement
String sql = "insert into hero values(null,?,?,?)";
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
// 根据sql语句创建PreparedStatement
//与Statement区别一
PreparedStatement ps = c.prepareStatement(sql);
) {
// 设置参数,与Statement区别二
ps.setString(1, "提莫");
ps.setFloat(2, 313.0f);
ps.setInt(3, 50);
// 执行
ps.execute();
}
Statement需要进行字符串拼接,可读性和维护性比较差
PreparedStatement使用参数设置,可读性好,不易犯错,有预编译机制性能较快
// Statement执行10次,需要10次把SQL语句传输到数据库端
// 数据库要对每一次来的SQL语句进行编译处理
for (int i = 0; i < 10; i++) {
String sql0 = "insert into hero values(null," + "'提莫'" + ","
+ 313.0f + "," + 50 + ")";
s.execute(sql0);
}
s.close();
// PreparedStatement 执行10次,只需要1次把SQL语句传输到数据库端
// 数据库对带?的SQL进行预编译
// 每次执行,只需要传输参数到数据库端
// 1. 网络传输量比Statement更小
// 2. 数据库不需要再进行编译,响应更快
for (int i = 0; i < 10; i++) {
ps.setString(1, "提莫");
ps.setFloat(2, 313.0f);
ps.setInt(3, 50);
ps.execute();
}
PreparedStatement还可以防止SQL注入式攻击
二.基本操作
1.查询
String sql = "select * from hero";
ResultSet rs = s.executeQuery(sql);
while(rs.next()){
int id = rs.getInt("id");//可以使用字段名
String name = rs.getString(2);//也可以使用字段的顺序,基1(Java自带的api里面唯二的基1的地方,另一个是PrepaeredStatement)
}
2.SQL语句判断账号密码是否正确
根据账号和密码到表中去找数据,
如果有数据,就表明密码正确了,
如果没数据,就表明密码错误。
String name = "dashen";
//正确的密码是:thisispassword
String password = "thisispassword1";
String sql = "select * from user where name = '" + name +"' and password = '" + password+"'";
// 执行查询语句,并把结果集返回给ResultSet
ResultSet rs = s.executeQuery(sql);
if(rs.next())
System.out.println("账号密码正确");
else
System.out.println("账号密码错误");
3.获取总数
String sql = "select count(*) from hero";
ResultSet rs = s.executeQuery(sql);
int total = 0;
while (rs.next()) {
total = rs.getInt(1); }
4.分页查询
String sql = "select * from hero limit " +start + "," + count;
start 表示开始页数,count表示一页显示的总数
start = 0, count = 5表示第一页,一共显示5条数据
start=10,count=5表示第三页,一共显示5条数据
三.其他
1.execute与executeUpdate的区别
在执行增,删,改时没区别
execute可以执行查询语句,把结果集取出来,返回boolean类型,true表示执行的是查询语句
executeUpdate不能执行查询语句返回int表示有多少条数据受到了影响
2.获取自增长id
PreparedStatement ps = c.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
//通常不用加Statement.RETURN_GENERATED_KEYS
// JDBC通过getGeneratedKeys获取该id
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
int id = rs.getInt(1);
System.out.println(id);
}
3.事务
在Mysql中,只有当表的类型是INNODB的时候,才支持事务,
在事务中的多个操作,要么都成功,要么都失败
通过 c.setAutoCommit(false);关闭自动提交
//这里有多个操作,要么都成功要么都失败
使用 c.commit();进行手动提交
4.ORM(Object Relationship Database Mapping),对象和关系数据库的映射
简单说,一个对象,对应数据库里的一条记录
5.DAO(DataAccess Object) 数据库访问对象
6.数据库连接池
1. ConnectionPool() 构造方法约定了这个连接池一共有多少连接
2. 在init() 初始化方法中,创建了size条连接。 注意,这里不能使用try-with-resource这种自动关闭连接的方式,因为连接恰恰需要保持不关闭状态,供后续循环使用
3. getConnection, 判断是否为空,如果是空的就wait等待,否则就借用一条连接出去
4. returnConnection, 在使用完毕后,归还这个连接到连接池,并且在归还完毕后,调用notifyAll,通知那些等待的线程,有新的连接可以借用了。
public class ConnectionPool {
List<Connection> cs = new ArrayList<Connection>();
int size;
public ConnectionPool(int size) {
this.size = size;
init();
}
public void init() {
//这里恰恰不能使用try-with-resource的方式,因为这些连接都需要是"活"的,不要被自动关闭了
try {
Class.forName("com.mysql.jdbc.Driver");
for (int i = 0; i < size; i++) {
Connection c = DriverManager
.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root", "admin");
cs.add(c);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized Connection getConnection() {
while (cs.isEmpty()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Connection c = cs.remove(0);
return c;
}
public synchronized void returnConnection(Connection c) {
cs.add(c);
this.notifyAll();
}
}
网友评论