Spring征服数据库
2019-11-05

一.spring的数据访问哲学

1. Srping的目标之一就是允许我们在开发应用程序的时候,能够遵循面向对象(Object Oriented,OO)原则中的"针对接口式编程";讲道理现在市面上的所有项目都离不开接口,针对接口是面向对象的重要特征之一,而spring的最终目标就是简化这一特征的使用方法(比如耦合).只暴露接口,从而体现出该实现的目标! 2. Spring的jdbcSpring为多种框架提供了jdbc支持;Spring本身就具有多个模块,他是模块化的框架,就好像java的虚拟机一样,在什么地方,用什么方法; 

二.配置数据源

1.不管使用什么模板,以及不管使用什么类型的数据库,数据源是必须的(废话),一般有三种方式;通过jdbc驱动程序定义的数据源(最基本的jdbc,注册驱动->获取连接->获取操作对象->操作结果集->释放资源);通过JNDL查找数据源(这个配置在服务器上面的比如TOMCAT),(留待)通过连接池获取数据源(c3p0,druid..)

三.jdbcTemplate (其实并不难,我指的是里面源码,很好理解,前提是理解回调和递归原则)

1.回调,它最难理解的地方之一    类A调用类B的方法B_1,然后A继续去执行自己的东西,B_1自己执行完了就告诉A,然后类A得到类B_1的执行结果,去做些不可描述的事情    小王在打游戏,叫小红去做饭,小红做了一会饭做好了,小王还在打游戏(这个时候小王可以决定吃饭,也可以继续打游戏,也可以边吃饭便打游戏(多线程异步))这之中的实现步骤,小王要实现一个接口,小红做好了饭就调用这个接口去告诉小王传递饭好了的信息,然而这个故事的主人公是小王,小红只是个配角,   换句话说如果小王没有叫小红去做饭那么小红是什么我们都不知道,小红之所以存在是因为小王他需要,所以要小红属于小王,小红对象依赖于小王对象而活,   在创建小王的同时就要将小红当做参数送给小王;  警察叔叔和贼的例子,因为警察想要教育贼,所以才有的贼回答问题(这个逻辑一点毛病都没有的)

//回调接口public interface CB { public void talk(String word);}

 

//警察叔叔类public class Police implements CB { private Thief tf ; //因为警察叔叔需要贼(要问问题),所以才有的贼(贼要回答问题),主业务需求,诞生附属子实现!!!! public Police(Thief tf) {//将贼对象传递给警察叔叔, this.tf = tf; } //回调方法,用来向当前类传递信息 @Override public void talk(String word) { System.out.println("毛贼说:" + word); } /** * 警察发问 */ public void talkcrap() { System.out.println("你错了吗"); tf.worng(this); //警察进行询问,这个贼是传入进来的,将当前类对象传递个贼,贼和警察是1对1关系(当然也可以实现1对多,使用LIist<贼对象>) }}

 

public class Thief { public void worng(CB cb) { //回调接口传递信息 cb.talk("警察叔叔我错了"); //这个地方传递的参数,当前行调用了接口的talk方法 }}

 

回调很绕,我解释不太清除,这个例子是自己想出来的,网上有很多大佬的解释,多敲几遍,多调试几遍代码,就能看懂里面的逻辑所在了;附上我修改过1对多例子

//回调接口public interface CallBack { //这里才是回调,要调用这个方法,才能够传递信息!!!!! public void tellAnswer(int answer);}//学生接口public interface Student { //这里放入一个对象,要放入主要对象,就是当前类依赖于的对象:主业务对象 public void resovleQuestion(CallBack callBack);}

 

//老师类public class Teacher implements CallBack { private List<Student> stus;//tom,lusy,rose public Teacher(List<Student> stus) { System.out.println("teacher对象创建,学生数量"+stus.size()); this.stus = stus; } @Override public void tellAnswer(int answer) { System.out.println(Thread.currentThread().getName()+"你的答案是" + answer); } public void askQuestion() { Thread.currentThread().setName("老师线程"); System.out.println("你们写了多长时间的作业?"); long end = 0; //启动所有线程,回答所有问题 for (int i = 0; i < stus.size(); i++) { new Thread((Runnable) stus.get(i)).start(); } try { System.out.println(Thread.currentThread().getName()+"开始休眠15秒,等待所有人的问题回答完"); Thread.sleep(15000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("老师线程休眠结束"+System.currentTimeMillis()); for (int i = 0; i < stus.size(); i++) { stus.get(i).resovleQuestion(this); } //当前类实现了回调接口,所以讲当前类对象传入进去//// long end = System.currentTimeMillis();// System.out.println("回答问题的时间:"+(end-start)); }}

 

  学生的实现类只需继承Student接口即可,其中使用了线程暂停来模拟思考题目的过程;sleep();  2.org.springframework.jdbc.core.RowMapper   将ResultSet封装成javaBeen类型,他是一个函数式接口

//将ResultSet封装成User类型public class RowMapperDemo implements RowMapper<User>{ @Override public User mapRow(ResultSet resultSet, int i) throws SQLException { User user = new User(); user.setName(resultSet.getString("name")); user.setPassword(resultSet.getString("password")); return user; }}

 

  3.方法总结execute方法:可以用于执行任何SQL语句,一般用于执行update,delete,insertupdate方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;call方法:用于执行存储过程、函数相关语句。   4. 最重要的还是回调    

//RowMapper接口将ResultSet里面的数据映射到JavaBeen中->封装数据 //queryforList(),执行SQL,将数据返回为List<Map<String(列名),Object(行数据))>> List<User> list = jt.query(sql, (rs ,i)-> new User(rs.getString("name"),rs.getString("password"))); new RowMapper<User>() { @Override public User mapRow(ResultSet resultSet, int i) throws SQLException { User user = new User(); user.setPassword(resultSet.getString("password")); user.setName(resultSet.getString("name")); return user; } };

 

   5. public <T> List<T> query(String sql, RowMapper<T> rowMapper):将执行的结果通过rowMapper接口映射为实体类对象

public List<Student> getStudents() { return jt.query("select * from student", (rs, i) -> new Student(rs.getString("stuno"), rs.getString("name"), rs.getInt("age"), rs.getString("address"))); //该lambda表达式相当于 new RowMapper<Student>() { @Override public Student mapRow(ResultSet resultSet, int i) throws SQLException { return new Student(rs.getString("stuno"),rs.getString("name"), rs.getInt("age"), rs.getString("address")); } }; }

 

6.public <T> T queryForObject(String sql, Class<T> requiredType)  一般用于单列查询,主要用来执行返回聚合函数的查询

jt.queryForObject("select count(*) from student where stuno =""+stuno+""", Integer.class);//返回Integer类型

 

     7.int update(String sql, @Nullable Object... args)   一般用来执行 更新,删除,增加操作,通配符使用方式如下

return jt.update("insert into student values(?,?,?,?)", new Object[]{stu.getStuno(), stu.getName(), stu.getAge(), stu.getAddress()});//这两种方式是一样的效果,简略了代码return jt.update("insert into student values(?,?,?,?)",stu.getStuno(), stu.getName(), stu.getAge(), stu.getAddress()); 8. execute语句,这种语句一般用来创建数据库,创建表那些,用于那种不复杂(不使用通配符"?")的语句

jt.execute("DELETE FROM student WHERE stuno = "" + stuno + """);不好使用通配符,这条sql半写死的,主要还是用来执行创建数据库,创建表的语句jt.update("DELETE FROM student WHERE stuno = ?",stuno);这两条语句的作用是一样的

 

  

9.我uml图画的不是很好,是在网上边学边画的,有问题请不吝赐教QAQ