packagecom.test;importcom.dao.ResumeDao;importcom.pojo.Resume;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.test.context.ContextConfiguration;importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;importjava.util.Optional;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations ={"classpath:spring.xml"})publicclassTest1{// 要测试IOC哪个对象注⼊即可@AutowiredprivateResumeDao resumeDao;/**
* dao层接⼝调⽤,分成两块:
* 1、基础的增删改查
* 2、专⻔针对查询的详细分析使⽤
*/@TestpublicvoidtestFindById(){// 早期的版本 dao.findOne(id); 可能现在没有了Optional<Resume> optional = resumeDao.findById(1l);Resume resume = optional.get();System.out.println(resume);/*
打印的结果(也包括sql语句):
Hibernate:
select
resume0_.id as id1_0_0_,
resume0_.address as address2_0_0_,
resume0_.name as name3_0_0_,
resume0_.phone as phone4_0_0_
from tb_resume resume0_ where resume0_.id=?
Resume{id=1, name='张三', address='北京', phone='131000000'}
很明显:对应的接口由于有对应的继承的泛型,那么会找到对应的类,然后通过类的信息进行处理
sql语句是:类名称0_.类变量 as 类变量递增数_0_0
类别名是:类名称0_
还有:@Table(name = "tb_resume")和@Column(name = "id")中id是作为sql中变量存在的,如果是iD,那么就是resume0_.iD,而id和iD在mysql中是没有影响的(表字段忽略大小写)
但是呢,他们是直接的指定,在mp中,是存在不指定,使用类来操作的,我们可以测试,发现他没有像mp一样的驼峰大小写,也就是说nAme就是nAme,不指定也算的(当然了,这些小细节忽略即可,没有必要的)
*/}}
直接进行访问,若出现了数据,代表操作成功,至此我们搭建好了环境的处理
我们继续学习:
继续在该测试类中补充如下:
@TestpublicvoidtestFindOne(){Resume resume =newResume();
resume.setId(1l);Example<Resume> of =Example.of(resume);Optional<Resume> one = resumeDao.findOne(of);//操作条件System.out.println(one.get());//get得到对应的Resume//当然了,对应get里面如果没有数据,会出现异常:/*
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
*///Optional在31章博客有点说明}
@TestpublicvoidtestFindAll(){List<Resume> all = resumeDao.findAll();//查询所有for(Resume resume : all){System.out.println(resume);}}@TestpublicvoidtestSort(){//设置id进行降序Sort sort =newSort(Sort.Direction.DESC,"id");//id是需要对应数据库的字段,他是在后面补充的,也可以说成是对应与注解,因为最终都是对应与数据库List<Resume> list = resumeDao.findAll(sort);for(int i =0; i < list.size(); i++){Resume resume = list.get(i);System.out.println(resume);}}
上面基本都是使用继承的接口的方法,我们也可以自定义一个:
回到前面的接口ResumeDao,在里面加上如下:
//可以引⼊jpql(jpa查询语⾔)语句进⾏查询,jpql 语句类似于sql,只不过sql操作的是数据表和字段,jpql操作的是对象和属性//⽐如 from Resume where id=xx(在hibernate中称为hql语句)@Query("from Resume where id =?1")//指定?,代表对应的给入的值,后面的1代表接口参数中的第一个//即?1代表使用Long idpublicList<Resume>findByJpql(Long id);
我们回到测试类,然后加上如下:
@TestpublicvoidtestJpql(){List<Resume> byJpql = resumeDao.findByJpql(6l);for(Resume s : byJpql){System.out.println(s);}/*
Hibernate:
select
resume0_.id as id1_0_,
resume0_.address as address2_0_,
resume0_.name as name3_0_,
resume0_.phone as phone4_0_
from tb_resume resume0_
where resume0_.id=?
Resume{id=6, name='让人', address='null', phone='null'}
对比一下这个:@Query("from Resume where id =?1")
很明显,这个注解是进行解析的,from Resume代表从这个类操作,这个类通常代表所在接口类对应继承的泛型来确定
后面的则是这个类对应的id的条件,和位置
还有,对应的接口可以不加返回值,只不过你不加的话,在扫描到这个注解时(对于dao层来说,对应的即有扫描,也有对应的直接读取,可以参考mybatis中对其dao的扫描操作(可以看看是否有注解),也可以参考106章博客)
进行执行时,自然也不会有返回值(反射),一般来说,如果考虑自动匹配一些返回值列表,通常需要代理(当然,代理的底层肯定是C完成),然后自行设置返回值
至此我们解释完毕
*/}
我们还可以继续补充参数:
@Query("from Resume where id =?1 and name = ?2")publicList<Resume>findByJpql(Long id,String name);//对应的Long id的id名称是可以随便写的
修改一下:
@TestpublicvoidtestJpql(){List<Resume> byJpql = resumeDao.findByJpql(6l,"让人");for(Resume s : byJpql){System.out.println(s);}}
进行测试吧,我们还可以操作原生的sql,我们在ResumeDao接口里面继续添加:
//默认情况下nativeQuery = true为false,代表操作jpql,设置为true,代表操作原生的//如果操作原生的,自然需要完整的sql,否则自然报错(sql报错,导致我们报错)@Query(value ="select * from tb_resume where id =?1 and name = ?2",nativeQuery =true)publicList<Resume>findBySql(Long id,String name);
继续测试:
@TestpublicvoidtestSql(){List<Resume> sql = resumeDao.findBySql(6l,"让人");for(Resume s : sql){System.out.println(s);}}
/*
方法命名规则查询
*/publicList<Resume>findByNameLike(String name);/*
select
resume0_.id as id1_0_,
resume0_.address as address2_0_,
resume0_.name as name3_0_,
resume0_.phone as phone4_0_
from tb_resume resume0_
where resume0_.name like ? escape ?
单独参数且默认情况下(具体为什么添加,可能还有其他原因,这里了解即可),如果escape什么都不操作,可以认为是空值,如''(上面只是打印sql,具体后面的拼接在底层代码里面,所以并不是全部需要看我们的参数的,有些可能有自动的处理的)
*/publicList<Resume>findByName(String name);/*
select
resume0_.id as id1_0_,
resume0_.address as address2_0_,
resume0_.name as name3_0_,
resume0_.phone as phone4_0_
from tb_resume resume0_
where resume0_.name=?
*///我们可以知道,对应的需要findBy开头,然后Name写上(首字母通常需要大写,否则报错,我测试了name,好像并不需要,但是还是建议大写,可能看版本),来确定操作谁,如果后面没有写具体的操作,如Like(首字母通常需要大写,否则报错),那么默认是等于的
@TestpublicvoidtestSpecification(){//动态条件封装Specification<Resume> objectSpecification =newSpecification(){//root:需要查询的对象属性//criteriaBuilder:构建查询条件@OverridepublicPredicatetoPredicate(Root root,CriteriaQuery criteriaQuery,CriteriaBuilder criteriaBuilder){//获取到name属性(会根据泛型找到对应类的)Path name = root.get("name");//构建条件Predicate predicate = criteriaBuilder.equal(name,"他");return predicate;}};/*
select
resume0_.id as id1_0_,
resume0_.address as address2_0_,
resume0_.name as name3_0_,
resume0_.phone as phone4_0_
from tb_resume resume0_
where resume0_.name=?
*///findOne只能让你查询一个,如果有多条数据,那么会报错Optional<Resume> one = resumeDao.findOne(objectSpecification);Resume resume = one.get();//没有找到会报错的System.out.println(resume);}
继续测试一下:
@TestpublicvoidtestSpecificationTest(){//动态条件封装Specification<Resume> objectSpecification =newSpecification(){//root:需要查询的对象属性//criteriaBuilder:构建查询条件@OverridepublicPredicatetoPredicate(Root root,CriteriaQuery criteriaQuery,CriteriaBuilder criteriaBuilder){//获取到name属性(会根据泛型找到对应类的)Path name = root.get("name");Path address = root.get("address");//构建条件Predicate predicate = criteriaBuilder.equal(name,"让人");Predicate predicate1 = criteriaBuilder.like(address.as(String.class),"分%");//告诉他,拼接的时候,是字符串//简单来说,如果address对应的类型不是String,那么转化成String,否则相当于不变(或者不写)//组合Predicate and = criteriaBuilder.and(predicate, predicate1);//有顺序的,predicate的在前面return and;}};/*
select
resume0_.id as id1_0_,
resume0_.address as address2_0_,
resume0_.name as name3_0_,
resume0_.phone as phone4_0_
from tb_resume resume0_
where resume0_.name=? and (resume0_.address like ?)
*/Optional<Resume> one = resumeDao.findOne(objectSpecification);Resume resume = one.get();//没有找到会报错的System.out.println(resume);}
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//packageorg.springframework.beans.factory;importorg.springframework.lang.Nullable;publicinterfaceFactoryBean<T>{@NullableTgetObject()throwsException;@NullableClass<?>getObjectType();defaultbooleanisSingleton(){returntrue;}}
publicBeanDefinitiongetBeanDefinition(String beanName)throwsNoSuchBeanDefinitionException{//也就是这个地方:beanDefinitionMap是存放bean信息的工厂,从里面拿取对应的bean信息(比如名称和全限定名称)BeanDefinition bd =(BeanDefinition)this.beanDefinitionMap.get(beanName);if(bd ==null){if(this.logger.isTraceEnabled()){this.logger.trace("No bean named '"+ beanName +"' found in "+this);}thrownewNoSuchBeanDefinitionException(beanName);}else{return bd;}}
我们找他put方法:
//就在当前类里面可以找到publicvoidregisterBeanDefinition(String beanName,BeanDefinition beanDefinition)throwsBeanDefinitionStoreException{//..Assert.hasText(beanName,"Bean name must not be empty");Assert.notNull(beanDefinition,"BeanDefinition must not be null");if(beanDefinition instanceofAbstractBeanDefinition){try{((AbstractBeanDefinition)beanDefinition).validate();}catch(BeanDefinitionValidationException var8){thrownewBeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,"Validation of bean definition failed", var8);}}//.. }
在上面的 Assert.notNull(beanDefinition, “BeanDefinition must not be null”);打上断点并加上条件(有beanName),看调用栈:
publicObjectgetProxy(@NullableClassLoader classLoader){returnthis.createAopProxy().getProxy(classLoader);}protectedfinalsynchronizedAopProxycreateAopProxy(){if(!this.active){this.activate();}//进入returnthis.getAopProxyFactory().createAopProxy(this);}publicAopProxycreateAopProxy(AdvisedSupport config)throwsAopConfigException{if(!config.isOptimize()&&!config.isProxyTargetClass()&&!this.hasNoUserSuppliedProxyInterfaces(config)){returnnewJdkDynamicAopProxy(config);}else{Class<?> targetClass = config.getTargetClass();if(targetClass ==null){thrownewAopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");}else{//看这里,可以发现对应是操作代理的return(AopProxy)(!targetClass.isInterface()&&!Proxy.isProxyClass(targetClass)?newObjenesisCglibAopProxy(config):newJdkDynamicAopProxy(config));}}}
return(Repository)this.repository.get();publicTget(){T value =this.getNullable();if(value ==null){thrownewIllegalStateException("Expected lazy evaluation to yield a non-null value but got null!");}else{return value;}}@NullableprivateTgetNullable(){T value =this.value;if(this.resolved){return value;}else{
value =this.supplier.get();this.value = value;this.resolved =true;return value;}}
🎇个人主页:Ice_Sugar_7 🎇所属专栏:计网 🎇欢迎点赞收藏加关注哦! IP 协议 🍉报头结构🍉地址管理🍌动态分配 IP 地址🍌NAT 机制(网络地址映射&am…