前言
一、jdbc是什么?
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
二、使用步骤
BufferedInputStream in = new BufferedInputStream(new FileInputStream("jdbc.properties"));
Properties p = new Properties();
p.load(in);
//1.注册驱动,加载驱动
Class.forName(p.getProperty("driver"));
//2.获得连接
String url = p.getProperty("url");
String user = p.getProperty("user");
String password = p.getProperty("password");
Connection connection = DriverManager.getConnection(url, user, password);
// System.out.println(connection);
//3.创建执行sql语句的对象
Statement statement = connection.createStatement();
String sql="select * from user1 where name like '%c%'";
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
System.out.println(resultSet.getString(1));
System.out.println(resultSet.getString(2));
System.out.println(resultSet.getString(3));
}
//释放资源
resultSet.close();
statement.close();
connection.close();
三、sql注入
举例:
"select * from user where user=‘张三’ and password=‘123456’ ";
"select * from user where user='asd ‘or 1=1#’ and password=‘123456’ ";
#号将and后面的代码全部注释了,这种情况不需要密码也可以登录和注册
解决方法:改变sql处理对象
Statement->preparedstatement
InputStream in = new BufferedInputStream(new FileInputStream("jdbc.properties"));
InputStreamReader inputStreamReader = new InputStreamReader(in);
Properties p = new Properties();
p.load( inputStreamReader);
//1.注册驱动,加载驱动
Class.forName(p.getProperty("driver"));
//2.获得连接
String url = p.getProperty("url");
String user = p.getProperty("user");
String password = p.getProperty("password");
Connection connection = DriverManager.getConnection(url, user, password);
// System.out.println(connection);
//3.创建执行sql语句的对象
String sql="select * from user1 where name =?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"cctv");
ResultSet resultSet = preparedStatement.executeQuery();
while(resultSet.next()){
System.out.println(resultSet.getString(1));
System.out.println(resultSet.getString(2));
System.out.println(resultSet.getString(3));
}
//释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
三、封装
静态代码块,在虚拟机加载类的时候就会加载执行,而且只执行一次;
class.getResourceAsStream
/表示上一次目录
1.封装连接工具类
2.封装日期工具类
防止反复映射对象
3.封装修改工具类
4.封装查询工具类(执行查询后返回的是一个集合,且该工具类不知道返回的对象类型及其对象属性,需要在执行查询方法时传入一个方法(自行实现映射对象)
apache有个封装类
好处:
在update操作时不用set方法对?赋值,而是在其QuerryRunner中做了封装,我们直接将参数放入数组中,传入即可。
在select操作时不用自己回调,
public class UserDaoimpl implements UserDao {
private QueryRunner queryRunner = new QueryRunner(DButils.getdatasourse());
@Override
public int insert(User user) throws SQLException {
Object[] parms={user.getLoginId(),user.getName(),user.getLoginPwd()};
int result=queryRunner.update("insert into user1(LoginId,Name,LoginPwd)values(?,?,?)",parms);
return result;
}
@Override
public int delete(int id) throws SQLException {
int update = queryRunner.update("delete from user1 where LoginId=?", id);
return update;
}
@Override
public long select() throws SQLException {
long query = queryRunner.query("select count(*) from user1", new ScalarHandler<>());
----------------
-ScalarHandler
-返回列的头一个值
-----------------
return query;
}
@Override
public User select(int LoginId) throws SQLException {
User query = queryRunner.query("select * from user1 where LoginId=?", new BeanHandler<User>(User.class), LoginId);
return query;
}
@Override
public List<User> selectall() throws SQLException {
List<User> query = queryRunner.query("select * from user1", new BeanListHandler<User>(User.class));
return query;
}
@Override
public int update() {
return 0;
}
}
注:使用这个apache下的工具类需要为bean类写无参构造方法
四、ORM(object rational mapping)
对象关系映射
创建一个类,将resultset数据放到类中。
在将包含中文的数据放入数据库中时,由于一般idea用的gbk编码,数据库用的是utf-8.。就需要改,可以直接在连接数据库这里改。
五、日期类
util包下的日期类是sql包下的日期类的子类。
1.从mysql中取出日期对象是sql包下的,可以直接赋值给POJO类的时期属性
2.将idea中的日期传给mysql时需要转化一下
步骤一:将字符串通过工具类转化为日期类
步骤二:再可以通过该日期类得到毫秒值
步骤三:最后传到sql包下日期类的构造函数中
六,事务
例如:银行取钱操作
当一个账户余额减除时,发生断电异常,此时需要事务回滚才行
如果设置提交事务为手动提交,那么假设后面既没有提交,也没有回滚。可能会导致表被锁住。
但是因为这里的连接对象很多,select方法中new了一个,update方法中也有,结果任然是余额减少了
解决思路
设置一个对象,该对像可以放一个连接对象,每次需要连接对象时就从中拿取一个。为啥不用单列类呢
估计是用了多线程后单例就不安全了;
实际上
注意:在这种方案下,所有用到的Dao层方法都不能关闭connection连接
具体了解Threadlocal
链接: link.
七,三层架构
当发现数据访问层中的实现类中的方法需要改进,或者需要另一个类来替换,那么就需要设置一个接口来约束方法的名称或参数。
一般要为数据访问层提供接口来约束方法。(面向接口编程)
八,连接池
public class pool {
//声明连接池对象
private static DruidDataSource ds;
static {
Properties p=new Properties();
try {
InputStream i= new BufferedInputStream(new FileInputStream("jdbc.properties"));
p.load(i);
ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(p);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接对象
public static Connection getconnection(){
try {
DruidPooledConnection connection = ds.getConnection();
return connection;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
public class pooltest {
public static void main(String[] args) throws SQLException {
for(int i=0;i<20;i++){
Connection c=pool.getconnection();
System.out.println(c);
c.close();//关闭=放回池中
//调用的是DruidPooledConnection中的close方法
}
}
}