一、mybatis和hibernate有什么不同
首先无论是mybatis还是hibernate都是通过配置文件,将数据库的表pojo映射起来的。mybatis和hibernate都可以称为ORM(对象关系映射)框架,只是hibernate是完全面向pojo的,而mybatis则不是,hibernate基本不需要编写sql就可以通过映射关系来操作数据库,是一种全表映射的体现,而mybatis则不同,它需要我们提供sql去运行。由于hibernate无须sql,当多表关联超过三个的时候,通过hibernate的级联会造成太多性能的丢失,而且如果查询语句中的子段是根据特定的条件变化的,而hibernate就无法支持这样的变化。
1.hibernate
首先通过hibernate的映射文件,将数据库中的表和pojo映射起来,然后通过对pojo操作,从而影响数据库的表。有自己的hql语句,提高效率
2.mybatis
首先mybatis提供了使用Mapper的接口编程,只要一个接口和一个xml就能创建映射。mybatis可以自由的书写sql,支持动态的sql,处理列表,动态的生成表名,支持存储过程,这样就可以灵活的定义查询语句,满足各类需求和性能优化的需求,缺点是工作量稍微大于hibernate。
二、java中的设计模式
Java 中一般认为有23种设计模式
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
1.单例者模式(懒汉式和饿汉式)
所谓的单例设计指的是一个类只允许产生一个实例化对象。
饿汉式:构造方法私有化,先创建对象
class Singleton {
/**
* 在类的内部可以访问私有结构,所以可以在类的内部产生实例化对象
*/
private static Singleton instance = new Singleton();
/**
* private 声明构造
*/
private Singleton() {
}
/**
* 返回对象实例
*/
public static Singleton getInstance() {
return instance;
}
}
懒汉式:构造方法私有,当第一使用的时候才去创建对象,存在线程安全问题,所以用到了 synchronized 来实现线程的同步,
class Singleton {
/**
* 声明变量
*/
private static volatile Singleton singleton = null;
/**
* 私有构造方法
*/
private Singleton() {
}
/**
* 提供对外方法
*/
public static Singleton getInstance() {
// 还未实例化
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
2.工厂设计模式(工厂方法模式和抽象工厂模式)
1.工厂方法模式
(1)普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
interface Sender {
void Send();
}
class AppleSender implements Sender {
@Override
public void Send() {
System.out.println("This is apple sender...");
}
}
class BananaSender implements Sender {
@Override
public void Send() {
System.out.println("This is banana sender...");
}
}
public class FactoryPattern {
public static void main(String[] args) {
Sender sender = produce("apple");
sender.Send();
}
public static Sender produce(String str) {
if ("apple".equals(str)) {
return new AppleSender();
} else if ("banana".equals(str)) {
return new BananaSender();
} else {
System.out.println("没有该类对象.");
return null;
}
}
}
(2) 多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
interface Sender {
void Send();
}
class AppleSender implements Sender {
@Override
public void Send() {
System.out.println("This is apple sender...");
}
}
class BananaSender implements Sender {
@Override
public void Send() {
System.out.println("This is banana sender...");
}
}
class SendFactory {
public Sender produceApple() {
return new AppleSender();
}
public Sender produceBanana() {
return new BananaSender();
}
}
public class FactoryPattern {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produceApple();
sender.Send();
}
} (3) 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
就是在上边的类SendFactory中的produceApple()方法前加static,然后在public FactoryPattern中直接调用produceApple()即可
2.抽象工厂模式
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要扩展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,那么这就用到了抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
interface Provider {
Sender produce();
}
interface Sender {
void Send();
}
class AppleSender implements Sender {
@Override
public void Send() {
System.out.println("This is apple sender...");
}
}
class BananaSender implements Sender {
@Override
public void Send() {
System.out.println("This is banana sender...");
}
}
class SendAppleFactory implements Provider {
public Sender produce() {
return new AppleSender();
}
}
class SendBananaFactory implements Provider {
public Sender produce() {
return new BananaSender();
}
}
public class FactoryPattern {
public static void main(String[] args) {
Provider provider = new SendAppleFactory();
Sender sender = provider.produce();
sender.Send();
}
}
3.建造者模式
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种类集中起来管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性。
public class TicketHelper{
public void buildAdult(String info){
System.out.println("构建成年人票逻辑"+info);
}
public void buildChildren(String info){
System.out.println("构建儿童票逻辑"+info);
}
public void buildElderly(String info){
System.out.println("构建老年人票逻辑"+info);
}
}
public class TicketBuilder{
public static Object builder(TicketHelper helper){
System.out.println("通过TicketHelper构建套票信息");
}
//测试
public static void mian(String [] args){
TicketHelper helper=new TicketHepler();
helper.buildAdult("成人票");
helper.buildChildren("儿童票");
helper.buildElderly("老年票");
Object ticket=TicketBuilder.builder(helper);
}
}
4.装饰者模式
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。装饰者模式就是再创一个类来加强主类的功能,这样的话就不用为每个子类创建子类来加强那个子类; 具体方法就是在新创的类中,声明一个主类,就像声明成员变量那样(主类名 变量名),然后重写新类的构造方法, 构造方法中将参数类型设置为主类的类型,然后写要加强的方法。调用时就直接调用新类并创建对象,然后调用新类的方法 就能实现加强的目的。
interface Shape {
void draw();
}
/**
* 实现接口的实体类
*/
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle...");
}
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle...");
}
}
/**
* 创建实现了 Shape 接口的抽象装饰类。
*/
abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape) {
this.decoratedShape = decoratedShape;
}
@Override
public void draw() {
decoratedShape.draw();
}
}
/**
* 创建扩展自 ShapeDecorator 类的实体装饰类。
*/
class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape) {
System.out.println("Border Color: Red");
}
}
5.代理模式(静态代理和动态代理)
代理模式指给一个对象提供一个代理对象,并由代理对象控制对原对象的引用。代理可以分为静态代理和动态代理。
通过代理模式,可以利用代理对象为被代理对象添加额外的功能,以此来拓展被代理对象的功能。可以用于计算某个方法执行时间,在某个方法执行前后记录日志等操作。
1. 静态代理
静态代理需要我们写出代理类和被代理类,而且一个代理类和一个被代理类一一对应。代理类和被代理类需要实现同一个接口,通过聚合使得代理对象中有被代理对象的引用,以此实现代理对象控制被代理对象的目的。
/**
* 代理类和被代理类共同实现的接口
*/
interface IService {
void service();
}
/**
* 被代理类
*/
class Service implements IService{
@Override
public void service() {
System.out.println("被代理对象执行相关操作");
}
}
/**
* 代理类
*/
class ProxyService implements IService{
/**
* 持有被代理对象的引用
*/
private IService service;
/**
* 默认代理Service类
*/
public ProxyService() {
this.service = new Service();
}
/**
* 也可以代理实现相同接口的其他类
* @param service
*/
public ProxyService(IService service) {
this.service = service;
}
@Override
public void service() {
System.out.println("开始执行service()方法");
service.service();
System.out.println("service()方法执行完毕");
}
}
//测试类
public class ProxyPattern {
public static void main(String[] args) {
IService service = new Service();
//传入被代理类的对象
ProxyService proxyService = new ProxyService(service);
proxyService.service();
}
}
2. 动态代理(jdk动态代理和cglib动态代理)一下使用的jdk动态代理和cglb动态代理的区别就是 jdk动态代理需要一个接口
JDK 1.3 之后,Java通过java.lang.reflect包中的三个类Proxy、InvocationHandler、Method来支持动态代理。动态代理常用于有若干个被代理的对象,且为每个被代理对象添加的功能是相同的(例如在每个方法运行前后记录日志)。
动态代理的代理类不需要我们编写,由Java自动产生代理类源代码并进行编译最后生成代理对象。
创建动态代理对象的步骤:
1. 指明一系列的接口来创建一个代理对象
2. 创建一个调用处理器(InvocationHandler)对象
3. 将这个代理指定为某个其他对象的代理对象
4. 在调用处理器的invoke()方法中采取代理,一方面将调用传递给真实对象,另一方面执行各种需要的操作
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理类和被代理类共同实现的接口
*/
interface IService {
void service();
}
class Service implements IService{
@Override
public void service() {
System.out.println("被代理对象执行相关操作");
}
}
class ServiceInvocationHandler implements InvocationHandler {
/**
* 被代理的对象
*代理对象和被代理对象之间的依赖关系
*/
private Object srcObject;
public ServiceInvocationHandler(Object srcObject) {
this.srcObject = srcObject;
}
/**
*代理逻辑
*/
@Override
public Object invoke(Object proxyObj, Method method, Object[] args) throws Throwable {
System.out.println("开始执行"+method.getName()+"方法");
//执行原对象的相关操作,容易忘记
Object returnObj = method.invoke(srcObject,args);
System.out.println(method.getName()+"方法执行完毕");
return returnObj;
}
}
public class ProxyPattern {
public static void main(String[] args) {
IService service = new Service();
Class<? extends IService> clazz = service.getClass();
IService proxyService = (IService) Proxy.newProxyInstance(clazz.getClassLoader(),
clazz.getInterfaces(), new ServiceInvocationHandler(service));
proxyService.service();
}
}
三、mybatis执行流程和底层原理
mybatis执行流程
1.在lib下导入java包
2.编写数据库中的表对应的pojo
3.编写mybatis和核心配置文件(加载mapper映射文件)
4.编写接口和对应的mapper映射文件(映射文件中的nameSpace是对应的接口的权限定名,查询语句中的id是接口中的方法名,parameterType是接口中方法的参数类型,resultType是接口中的方法的返回值,也可以是resultMap编写的pojo中的成员变量和数据库表字段的对应关系)
5.然后通过核心配置文件中的mapper和mapper映射文件实现映射器,主要pojo属性和表字段对应,就可以自动映射。
1.在查询语句中可以使用注解传递多个参数 @param 如果数据过多的话 使用pojo
2.#和$ 如果表名是变化的则必须使用$,order by 后必须使用$
3.一对一的级联 在mapper映射文件中 通过association 元素代表一对一级联的开始,property代表映射到的pojo属性,column代表sql列,select配置对应的命名空间,这样便可以指出对应mapper的sql,mybatis就会通过对应的sql将数据查询回来
<asscoiation property="task" column="task_id" select="task的mapper的接口的全路径名称下的要查询的那个方法" /asscoiation>
一对多的级联 在mapper映射文件中 通过collection配置,并且在pojo中 一的一方配置多的一方的组合用集合的方式,property代表一的一方中组合的属性名,
4.延迟加载 lazyLoadingEnabled默认是false,和 aggressiveLazyLoading 默认false
5.动态sql,choose,when,otherwise, trim, where,set,foreach
底层原理
通过动态代理实现mapper自动映射
四、Spring (spring IOC 和 Spring AOP)
spring依赖注入的三种方式:1.构造器注入 2.setter注入 3.接口注入
spring装配bean的三种方式:1.在xml中显示配置 2.在java接口和类中实现配置 3.隐式Bean的发现机制和自动装配原则
使用xml装配bean,只需要在配置文件中编写 bean标签,里边配置property 的name 和 value
通过注解装配bean,@Component,代表 spring ioc会把这个类扫描成bean实例,这样spring ioc 并不知道去哪里扫描,所以就有@ComponentScan 代表全表扫描,默认是当前包的路径。 -----这个一般不使用
@Autowired(required="false|true")默认是true就是必须注入成功, 自动装配,如果一个接口下不只有一个实现类的话,使用在动装配存在歧义,所以使用@Primary和@Qualifier,注解@Primary写在具体的实现类上,代表这个类优先注入,但是这并不能解决实际问题,可以 使用@Qualifier(“在具体的实现类中起的别名”)写在@Autowired的下边
Spring IOC 底层采用是反射,IOC的设计是基于BeanFactory