精华内容
下载资源
问答
  • 主要介绍了Laravel5.1 框架模型一对一关系实现与使用方法,结合实例形式分析了laravel5.1框架模型一对一关系的原理、定义与使用方法,需要的朋友可以参考下
  • 设计个只能创建个唯一实例的类——单例模式 1. 背景  老师布置了个思考题:设计个只能创建个唯一实例的类。让我们只要想一下思路即可。自己的第反应就是设计模式中的单例模式。自己百度了一下单例...

    设计一个只能创建一个唯一实例的类——单例模式


    1. 背景


         老师布置了一个思考题:设计一个只能创建一个唯一实例的类。让我们只要想一下思路即可。自己的第一反应就是设计模式中的单例模式。自己百度了一下单例模式,下面附上自己百度到的认为最好的一篇文章。


    2.备注


         转载主要出自:作者刘伟。链接为:http://blog.csdn.net/lovelion。特在此说明


    3.具体内容



    3.1 单例模式的动机

          对于一个软件系统的某些类而言,我们无须创建多个实例。举个大家都熟知的例子——Windows任务管理器,如图3-1所示,我们可以做一个这样的尝试,在Windows的“任务栏”的右键弹出菜单上多次点击“启动任务管理器”,看能否打开多个任务管理器窗口?如果你的桌面出现多个任务管理器,我请你吃饭,微笑(注:电脑中毒或私自修改Windows内核者除外)。通常情况下,无论我们启动任务管理多少次,Windows系统始终只能弹出一个任务管理器窗口,也就是说在一个Windows系统中,任务管理器存在唯一性。为什么要这样设计呢?我们可以从以下两个方面来分析:其一,如果能弹出多个窗口,且这些窗口的内容完全一致,全部是重复对象,这势必会浪费系统资源,任务管理器需要获取系统运行时的诸多信息,这些信息的获取需要消耗一定的系统资源,包括CPU资源及内存资源等,浪费是可耻的,而且根本没有必要显示多个内容完全相同的窗口;其二,如果弹出的多个窗口内容不一致,问题就更加严重了,这意味着在某一瞬间系统资源使用情况和进程、服务等信息存在多个状态,例如任务管理器窗口A显示“CPU使用率”为10%,窗口B显示“CPU使用率”为15%,到底哪个才是真实的呢?这纯属“调戏”用户,给用户带来误解,更不可取。由此可见,确保Windows任务管理器在系统中有且仅有一个非常重要。


                                                                           图3-1 Windows任务管理器


     回到实际开发中,我们也经常遇到类似的情况,为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现,这就是单例模式的动机所在。

     

    3.2 单例模式概述

          下面我们来模拟实现Windows任务管理器,假设任务管理器的类名为TaskManager,在TaskManager类中包含了大量的成员方法,例如构造函数TaskManager(),显示进程的方法displayProcesses(),显示服务的方法displayServices()等,该类的示意代码如下:


    class TaskManager
    {
         public TaskManager() {……} //初始化窗口
         public void displayProcesses()  {……} //显示进程
         public void  displayServices() {……} //显示服务
         ……
    }

    为了实现Windows任务管理器的唯一性,我们通过如下三步来对该类进行重构:

          (1)  由于每次使用new关键字来实例化TaskManager类时都将产生一个新对象,为了确保TaskManager实例的唯一性,我们需要禁止类的外部直接使用new来创建对象,因此需要将TaskManager的构造函数的可见性改为private,如下代码所示:


    private TaskManager() {……}

           (2)   将构造函数改为private修饰后该如何创建对象呢?不要着急,虽然类的外部无法再使用new来创建对象,但是在TaskManager的内部还是可以创建的,可见性只对类外有效。因此,我们可以在TaskManager中创建并保存这个唯一实例。为了让外界可以访问这个唯一实例,需要在TaskManager中定义一个静态的TaskManager类型的私有成员变量,如下代码所示:


    private static TaskManager tm = null;

         (3)   为了保证成员变量的封装性,我们将 TaskManager 类型的 tm 对象的可见性设置为 private ,但外界该如何使用该成员变量并何时实例化该成员变量呢?答案是增加一个公有的静态方法,如下代码所示:


    public static TaskManager getInstance()
    {
        if (tm == null)
        {
            tm = new TaskManager();
        }
        return tm;
    }

           在getInstance()方法中首先判断tm对象是否存在,如果不存在(即tm == null),则使用new关键字创建一个新的TaskManager类型的tm对象,再返回新创建的tm对象;否则直接返回已有的tm对象。

          需要注意的是getInstance()方法的修饰符,首先它应该是一个public方法,以便供外界其他对象使用,其次它使用了static关键字,即它是一个静态方法,在类外可以直接通过类名来访问,而无须创建TaskManager对象,事实上在类外也无法创建TaskManager对象,因为构造函数是私有的。 

     

    思考

    为什么要将成员变量tm定义为静态变量?

           通过以上三个步骤,我们完成了一个最简单的单例类的设计,其完整代码如下:


    class TaskManager
    {
         private static TaskManager tm = null;
         private TaskManager() {……} //初始化窗口
         public void  displayProcesses() {……} //显示进程
         public void  displayServices() {……} //显示服务
         public static TaskManager getInstance()
         {
            if (tm == null)
            {
                tm = new TaskManager();
            }
            return tm;
        }
       ……
    }

           在类外我们无法直接创建新的TaskManager对象,但可以通过代码TaskManager.getInstance()来访问实例对象,第一次调用getInstance()方法时将创建唯一实例,再次调用时将返回第一次创建的实例,从而确保实例对象的唯一性。

          上述代码也是单例模式的一种最典型实现方式,有了以上基础,理解单例模式的定义和结构就非常容易了。单例模式定义如下: 

    单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。

          单例模式有三个要点:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

           单例模式是结构最简单的设计模式一,在它的核心结构中只包含一个被称为单例类的特殊类。单例模式结构如图3-2所示:

          单例模式结构图中只包含一个单例角色:

          ● Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。


    3.3 负载均衡器的设计与实现

           Sunny软件公司承接了一个服务器负载均衡(Load Balance)软件的开发工作,该软件运行在一台负载均衡服务器上,可以将并发访问和数据流量分发到服务器集群中的多台设备上进行并发处理,提高系统的整体处理能力,缩短响应时间。由于集群中的服务器需要动态删减,且客户端请求需要统一分发,因此需要确保负载均衡器的唯一性,只能有一个负载均衡器来负责服务器的管理和请求的分发,否则将会带来服务器状态的不一致以及请求分配冲突等问题。如何确保负载均衡器的唯一性是该软件成功的关键。

          Sunny公司开发人员通过分析和权衡,决定使用单例模式来设计该负载均衡器,结构图如图3-3所示:

             在图3-3中,将负载均衡器LoadBalancer设计为单例类,其中包含一个存储服务器信息的集合serverList,每次在serverList中随机选择一台服务器来响应客户端的请求,实现代码如下所示:

    import java.util.*;
    
    //负载均衡器LoadBalancer:单例类,真实环境下该类将非常复杂,包括大量初始化的工作和业务方法,考虑到代码的可读性和易理解性,只列出部分与模式相关的核心代码
    class LoadBalancer {
    	//私有静态成员变量,存储唯一实例
    	private static LoadBalancer instance = null;
    	//服务器集合
    	private List serverList = null;
    	
    	//私有构造函数
    	private LoadBalancer() {
    		serverList = new ArrayList();
    	}
    	
    	//公有静态成员方法,返回唯一实例
    	public static LoadBalancer getLoadBalancer() {
    		if (instance == null) {
    			instance = new LoadBalancer();
    		}
    		return instance;
    	}
    	
    	//增加服务器
    	public void addServer(String server) {
    		serverList.add(server);
    	}
    	
    	//删除服务器
    	public void removeServer(String server) {
    		serverList.remove(server);
    	}
    	
    	//使用Random类随机获取服务器
    	public String getServer() {
    		Random random = new Random();
    		int i = random.nextInt(serverList.size());
    		return (String)serverList.get(i);
    	}
    }


         编写如下客户端测试代码:


    class Client {
    	public static void main(String args[]) {
            //创建四个LoadBalancer对象
    		LoadBalancer balancer1,balancer2,balancer3,balancer4;
    		balancer1 = LoadBalancer.getLoadBalancer();
    		balancer2 = LoadBalancer.getLoadBalancer();
    		balancer3 = LoadBalancer.getLoadBalancer();
    		balancer4 = LoadBalancer.getLoadBalancer();
    		
    		//判断服务器负载均衡器是否相同
    		if (balancer1 == balancer2 && balancer2 == balancer3 && balancer3 == balancer4) {
    			System.out.println("服务器负载均衡器具有唯一性!");
    		}
    		
    		//增加服务器
    		balancer1.addServer("Server 1");
    		balancer1.addServer("Server 2");
    		balancer1.addServer("Server 3");
    		balancer1.addServer("Server 4");
    		
    		//模拟客户端请求的分发
    		for (int i = 0; i < 10; i++) {
                String server = balancer1.getServer();
    			System.out.println("分发请求至服务器: " + server);
          }
    	}
    }


            编译并运行程序,输出结果如下:

    服务器负载均衡器具有唯一性!

    分发请求至服务器:  Server 1

    分发请求至服务器:  Server 3

    分发请求至服务器:  Server 4

    分发请求至服务器:  Server 2

    分发请求至服务器:  Server 3

    分发请求至服务器:  Server 2

    分发请求至服务器:  Server 3

    分发请求至服务器:  Server 4

    分发请求至服务器:  Server 4

    分发请求至服务器:  Server 1

            虽然创建了四个LoadBalancer对象,但是它们实际上是同一个对象,因此,通过使用单例模式可以确保LoadBalancer对象的唯一性。


    3.4 饿汉式单例与懒汉式单例的讨论

          Sunny公司开发人员使用单例模式实现了负载均衡器的设计,但是在实际使用中出现了一个非常严重的问题,当负载均衡器在启动过程中用户再次启动该负载均衡器时,系统无任何异常,但当客户端提交请求时出现请求分发失败,通过仔细分析发现原来系统中还是存在多个负载均衡器对象,导致分发时目标服务器不一致,从而产生冲突。为什么会这样呢?Sunny公司开发人员百思不得其解。

          现在我们对负载均衡器的实现代码进行再次分析,当第一次调用getLoadBalancer()方法创建并启动负载均衡器时,instance对象为null值,因此系统将执行代码instance= new LoadBalancer(),在此过程中,由于要对LoadBalancer进行大量初始化工作,需要一段时间来创建LoadBalancer对象。而在此时,如果再一次调用getLoadBalancer()方法(通常发生在多线程环境中),由于instance尚未创建成功,仍为null值,判断条件(instance== null)为真值,因此代码instance= new LoadBalancer()将再次执行,导致最终创建了多个instance对象,这违背了单例模式的初衷,也导致系统运行发生错误。

          如何解决该问题?我们至少有两种解决方案,在正式介绍这两种解决方案之前,先介绍一下单例类的两种不同实现方式,饿汉式单例类和懒汉式单例类。

     

    1.饿汉式单例类

          饿汉式单例类是实现起来最简单的单例类,饿汉式单例类结构图如图3-4所示:

            从图3-4中可以看出,由于在定义静态变量的时候实例化单例类,因此在类加载的时候就已经创建了单例对象,代码如下所示:

    class EagerSingleton { 
        private static final EagerSingleton instance = new EagerSingleton(); 
        private EagerSingleton() { } 
    
        public static EagerSingleton getInstance() {
            return instance; 
        }   
    }

          当类被加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。如果使用饿汉式单例来实现负载均衡器LoadBalancer类的设计,则不会出现创建多个单例对象的情况,可确保单例对象的唯一性。
     

    2.懒汉式单例类与线程锁定

          除了饿汉式单例,还有一种经典的懒汉式单例,也就是前面的负载均衡器LoadBalancer类的实现方式。懒汉式单例类结构图如图3-5所示:

          从图3-5中可以看出,懒汉式单例在第一次调用getInstance()方法时实例化,在类加载时并不自行实例化,这种技术又称为延迟加载(Lazy Load)技术,即需要的时候再加载实例,为了避免多个线程同时调用getInstance()方法,我们可以使用关键字synchronized,代码如下所示:
    [java]  view plain copy
    1. class LazySingleton {   
    2.     private static LazySingleton instance = null;   
    3.   
    4.     private LazySingleton() { }   
    5.   
    6.     synchronized public static LazySingleton getInstance() {   
    7.         if (instance == null) {  
    8.             instance = new LazySingleton();   
    9.         }  
    10.         return instance;   
    11.     }  
    12. }  


          该懒汉式单例类在getInstance()方法前面增加了关键字synchronized进行线程锁,以处理多个线程同时访问的问题。但是,上述代码虽然解决了线程安全问题,但是每次调用getInstance()时都需要进行线程锁定判断,在多线程高并发访问环境中,将会导致系统性能大大降低。如何既解决线程安全问题又不影响系统性能呢?我们继续对懒汉式单例进行改进。事实上,我们无须对整个getInstance()方法进行锁定,只需对其中的代码“instance = new LazySingleton();”进行锁定即可。因此getInstance()方法可以进行如下改进:
    [java]  view plain copy
    1. public static LazySingleton getInstance() {   
    2.     if (instance == null) {  
    3.         synchronized (LazySingleton.class) {  
    4.             instance = new LazySingleton();   
    5.         }  
    6.     }  
    7.     return instance;   
    8. }  
           问题貌似得以解决,事实并非如此。如果使用以上代码来实现单例,还是会存在单例对象不唯一。原因如下:

          假如在某一瞬间线程A和线程B都在调用getInstance()方法,此时instance对象为null值,均能通过instance == null的判断。由于实现了synchronized加锁机制,线程A进入synchronized锁定的代码中执行实例创建代码,线程B处于排队等待状态,必须等待线程A执行完毕后才可以进入synchronized锁定代码。但当A执行完毕时,线程B并不知道实例已经创建,将继续创建新的实例,导致产生多个单例对象,违背单例模式的设计思想,因此需要进行进一步改进,在synchronized中再进行一次(instance == null)判断,这种方式称为双重检查锁定(Double-Check Locking)。使用双重检查锁定实现的懒汉式单例类完整代码如下所示:

    [java]  view plain copy
    1. class LazySingleton {   
    2.     private volatile static LazySingleton instance = null;   
    3.   
    4.     private LazySingleton() { }   
    5.   
    6.     public static LazySingleton getInstance() {   
    7.         //第一重判断  
    8.         if (instance == null) {  
    9.             //锁定代码块  
    10.             synchronized (LazySingleton.class) {  
    11.                 //第二重判断  
    12.                 if (instance == null) {  
    13.                     instance = new LazySingleton(); //创建单例实例  
    14.                 }  
    15.             }  
    16.         }  
    17.         return instance;   
    18.     }  
    19. }  

           需要注意的是,如果使用双重检查锁定来实现懒汉式单例类,需要在静态成员变量instance之前增加修饰符volatile,被volatile修饰的成员变量可以确保多个线程都能够正确处理,且该代码只能在JDK 1.5及以上版本中才能正确执行。由于volatile关键字会屏蔽Java虚拟机所做的一些代码优化,可能会导致系统运行效率降低,因此即使使用双重检查锁定来实现单例模式也不是一种完美的实现方式。 

     

    扩展

    IBM公司高级软件工程师Peter    Haggar 2004年在IBM developerWorks上发表了一篇名为《双重检查锁定及单例模式——全面理解这一失效的编程习语》的文章,对JDK    1.5之前的双重检查锁定及单例模式进行了全面分析和阐述,参考链接:http://www.ibm.com/developerworks/cn/java/j-dcl.html

     

    3.饿汉式单例类与懒汉式单例类比较

          饿汉式单例类在类被加载时就将自己实例化,它的优点在于无须考虑多线程访问问题,可以确保实例的唯一性;从调用速度和反应时间角度来讲,由于单例对象一开始就得以创建,因此要优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲,饿汉式单例不及懒汉式单例,而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。

          懒汉式单例类在第一次使用时创建,无须一直占用系统资源,实现了延迟加载,但是必须处理好多个线程同时访问的问题,特别是当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费大量时间,这意味着出现多线程同时首次引用此类的机率变得较大,需要通过双重检查锁定等机制进行控制,这将导致系统性能受到一定影响。


    3.5 一种更好的单例实现方法

           饿汉式单例类不能实现延迟加载,不管将来用不用始终占据内存;懒汉式单例类线程安全控制烦琐,而且性能受影响。可见,无论是饿汉式单例还是懒汉式单例都存在这样那样的问题,有没有一种方法,能够将两种单例的缺点都克服,而将两者的优点合二为一呢?答案是:Yes!下面我们来学习这种更好的被称之为Initializationon Demand Holder (IoDH)的技术。

          在IoDH中,我们在单例类中增加一个静态(static)内部类,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用,实现代码如下所示:

    [java]  view plain copy
    1. //Initialization on Demand Holder  
    2. class Singleton {  
    3.     private Singleton() {  
    4.     }  
    5.       
    6.     private static class HolderClass {  
    7.             private final static Singleton instance = new Singleton();  
    8.     }  
    9.       
    10.     public static Singleton getInstance() {  
    11.         return HolderClass.instance;  
    12.     }  
    13.       
    14.     public static void main(String args[]) {  
    15.         Singleton s1, s2;   
    16.             s1 = Singleton.getInstance();  
    17.         s2 = Singleton.getInstance();  
    18.         System.out.println(s1==s2);  
    19.     }  
    20. }  

           编译并运行上述代码,运行结果为:true,即创建的单例对象s1s2为同一对象。由于静态单例对象没有作为Singleton的成员变量直接实例化,因此类加载时不会实例化Singleton,第一次调用getInstance()时将加载内部类HolderClass,在该内部类中定义了一个static类型的变量instance,此时会首先初始化这个成员变量,由Java虚拟机来保证其线程安全性,确保该成员变量只能初始化一次。由于getInstance()方法没有任何线程锁定,因此其性能不会造成任何影响。

          通过使用IoDH,我们既可以实现延迟加载,又可以保证线程安全,不影响系统性能,不失为一种最好的Java语言单例模式实现方式(其缺点是与编程语言本身的特性相关,很多面向对象语言不支持IoDH)。

     

    练习

    分别使用饿汉式单例、带双重检查锁定机制的懒汉式单例以及IoDH技术实现负载均衡器LoadBalancer

          至此,三种单例类的实现方式我们均已学习完毕,它们分别是饿汉式单例、懒汉式单例以及IoDH


    3.6 单例模式总结

           单例模式作为一种目标明确、结构简单、理解容易的设计模式,在软件开发中使用频率相当高,在很多应用软件和框架中都得以广泛应用。

     

    1.主要优点

           单例模式的主要优点如下:

           (1) 单例模式提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它。

           (2) 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。

           (3) 允许可变数目的实例。基于单例模式我们可以进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例,既节省系统资源,又解决了单例单例对象共享过多有损性能的问题。

     

    2.主要缺点

           单例模式的主要缺点如下:

           (1) 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。

           (2) 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。

           (3) 现在很多面向对象语言(JavaC#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的共享对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致共享的单例对象状态的丢失。

     

    3.适用场景

           在以下情况下可以考虑使用单例模式:

           (1) 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。

           (2) 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

     

    思考

    如何对单例模式进行改造,使得系统中某个类的对象可以存在有限多个,例如两例或三例?【注:改造之后的类可称之为多例类。】



    展开全文
  • 一对一、一对多、多对多模型关系的建立和增删改查要注意的问题 一对一: 1.在维护关系的一方使用:models.OneToOneField(另一个一方模型类名称,on_delete=models.CASCADE) eg: from django.db import models ...

    一对一、一对多、多对多模型关系的建立和增删改查要注意的问题

    一对一:

    1.在维护关系的一方使用:models.OneToOneField(另一个一方模型类名称,on_delete=models.CASCADE)

    eg:

    from django.db import models
    
    class Wife(models.Model):
        name = models.CharField(max_length=10)
        age = models.IntegerField()
        
        #重写
        def __str__(self):
            return self.name
    
        #表的重命名
        class Meta:
            db_table = 'a_wife'
    
    class Husband(models.Model):
        name = models.CharField(max_length=10)
        age = models.IntegerField()
    
        #一对一关联
        o2o = models.OneToOneField(Wife,on_delete=models.CASCADE)
    
        def __str__(self):
            return self.name
    
        class Meta:
            db_table = 'a_husband'

    2.非维护关系的一方模型对象创建:

       1)变量名 = 非维护关系的一方对象模型名.对象管理器(非自定义默认为objects).create(字段名=值,...)

       2)非维护关系的一方对象模型名.对象管理器(非自定义默认为objects).create(字段名=值,...)

       3)变量名 = 非维护关系的一方对象模型名(字段名=值,...)

          变量名.save()进行保存

    维护关系一方的模型的创建:

    1)通过非维护关系一方的实例化对象关联

    变量名 = 维护关系一方模型对象名.对象管理器(非自定义默认为objects).create(字段名=值,...关联变量名=非维护关系一方实例变量名)

    2)通过对应表的外键关联

    变量名 = 维护关系一方模型对象名.对象管理器(非自定义默认为objects).create(字段名=值,...关联变量名_非维护关系一方主键字段名=非维护关系一方主键字段值)

    eg:

    # 1)
    w1=Wife.objects.create(name='小妖',age=25);
    # 2)
    Wife.objects.create(name='小妖',age=25);
    # 3)
    w3=Wife(name='小妖',age=25);
    w3.save()
    

    3.非维护关系的一方模型对象的删除:

       变量名 = 非维护关系的一方对象模型名.对象管理器(非自定义默认为objects).git(字段名=值,...)

       变量名.delete()

    eg:

    #在不维护关系的一方进行删除时:因为在维护关系的一方与其进行了关联,即在维护关系的一方有其数据的存在,所以不维护关系一方的数据删除后,维护关系的一方的与其有关联的数据也会一并删除
    #在维护关系的一方进行删除时,则不会影响不维护关系一方的表的数据
    d2=Wife.objects.get(id=2);
    
    d2.delete();
    

    4.非维护关系的一方模型对象的修改:

       先进行查找:变量名 = 非维护关系的一方对象模型名.对象管理器(非自定义默认为objects).git(字段名=值,...)

       变量名.字段名 = 修改后的值

       变量名.save()

    eg:

    h=Husband.objects.get(id=2);
    
    h.name='颙颜';
    
    h.save()
    

     

               5.其实查找问题一直贯穿其它几个操作之中。

    一对多:

    1.模型建立需要注意:多方模型内创建外键类属性,关联一方:

    变量名 = models.ForeignKey(一方模型类名称,on_delete=models.CASCADE)

    2.模型创建:

    一方:参考一对一中的创建

    多方:

    1)通过“一”方的实例化对象关联

    2)通过对应表的外键关联

    3)通过“一”方添加对象:变量名 = 一方实例化对象.多方对象模型名_set.create(字段名=值,...)

    3.查询:

    从一方查询多方:使用“多”方模型类小写_set,作为“一”方容器。

    从“多”方查询“一”方: 使用“多”方外键属性直接获取对应的“一”方实例

    4.删除、修改就是基本的操作

    多对多:

    1.多方创建模型关系

    models.ManyToManyField(另一个多方模型类,through="中间关系模型类")

    eg:

    #在中间模型类中至少有两个外键类属性,分别关联两个多方模型。
         
         class Student(models.Model):
               pass
    
         class Course(models.Model):
             name = models.CharField(max_length=10)
             stu = models.ManyToManyField(Student,through="Student_Course") # 多对多关系
    
         class Student_Course(models.Model):   # 中间模型,负责维护两个“多方”模型
             student = models.ForeignKey(Student,on_delete=models.CASCADE)  # 关联Student模型的外键
             course = models.ForeignKey(Course,on_delete=models.CASCADE) # 关联Course模型的外键
             score = models.FloatField()

    2.维护关系的和不负责维护关系的创建都是通过基本的创建方式实现

    第三方关系表的创建则可以用实例化对象关联和外键值关联

        #使用实例化对象关联
           sc1 = Student_Course.objects.create(student=stu1,course=course1,score=85)
        #使用外键值关联
           sc3 = Student_Course.objects.create(student_id=3,course_id=1,score=69)

    3.查询:

    从不负责的多方查询另一个多方

        #例如:1号学生选的课程
            student1 = Student.objects.get(id=1)
            courses = student1.course_set.all()  # 对方模型类小写_set

    从负责关联的多方查询另一个多方
           

        #例如:查询选择2号课程的学生
           course2 = Course.objects.get(id=2)
           students = course2.stu.all()  # stu为关联类属性

    4.修改和删除就是基本的操作

    展开全文
  • 一个项目对应多个学生 一个学生对应多个项目(多对多关系) ...实现多对多关系,必须要第三表来操作,且它们都属于外键。...一个项目对应一个老师(一对关系) 导师表 项目表
     
    
    一个项目对应多个学生
    一个学生对应多个项目(多对多关系)

    项目表学生表
    项目号(主) 学生号(主)
    学生-项目表
    项目号(外) 学生号(外)
    实现多对多关系,必须要第三表来操作,且它们都属于外键。


    一个导师对应多个项目
    一个项目对应一个老师(一对多关系)
    导师表项目表
    导师号(主) 项目号(主)
    导师号(外)
    实现一对多关系,只需在多关系中把一关系作为外键即可。
    展开全文
  • 深入理解单例模式——只有实例

    万次阅读 多人点赞 2018-05-25 19:32:06
    初遇设计模式在上个寒假,当时把每个设计模式过了遍,设计模式有了个最初级的了解。这个学期借了几本设计模式的书籍看,听了老师的设计模式课,设计模式算是有个更进一步的认识。后面可能会不定期更新一下...

    我自己总结的Java学习的系统知识点以及面试问题,已经开源,目前已经 35k+ Star。会一直完善下去,欢迎建议和指导,同时也欢迎Star: https://github.com/Snailclimb/Java-Guide

    前言

    初遇设计模式在上个寒假,当时把每个设计模式过了一遍,对设计模式有了一个最初级的了解。这个学期借了几本设计模式的书籍看,听了老师的设计模式课,对设计模式算是有个更进一步的认识。后面可能会不定期更新一下自己对于设计模式的理解。每个设计模式看似很简单,实则想要在一个完整的系统中应用还是非常非常难的。然后我的水品也非常非常有限,代码量也不是很多,只能通过阅读书籍、思考别人的编码经验以及结合自己的编码过程中遇到的问题来总结。

    怎么用->怎么用才好->怎么与其他模式结合使用,我想这是每个开发人员都需要逾越的一道鸿沟。

    一 单例模式简介

    1.1 定义

    保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    1.2 为什么要用单例模式呢?

    在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。

    简单来说使用单例模式可以带来下面几个好处:

    • 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
    • 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。

    1.3 为什么不使用全局变量确保一个类只有一个实例呢?

    我们知道全局变量分为静态变量和实例变量,静态变量也可以保证该类的实例只存在一个。
    只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。

    但是,如果说这个对象非常消耗资源,而且程序某次的执行中一直没用,这样就造成了资源的浪费。利用单例模式的话,我们就可以实现在需要使用时才创建对象,这样就避免了不必要的资源浪费。 不仅仅是因为这个原因,在程序中我们要尽量避免全局变量的使用,大量使用全局变量给程序的调试、维护等带来困难。

    二 单例的模式的实现

    通常单例模式在Java语言中,有两种构建方式:

    • 饿汉方式。指全局的单例实例在类装载时构建
    • 懒汉方式。指全局的单例实例在第一次被使用时构建。

    不管是那种创建方式,它们通常都存在下面几点相似处:

    • 单例类必须要有一个 private 访问级别的构造函数,只有这样,才能确保单例不会在系统中的其他代码内被实例化;
    • instance 成员变量和 uniqueInstance 方法必须是 static 的。

    2.1 饿汉方式(线程安全)

        public class Singleton {
           //在静态初始化器中创建单例实例,这段代码保证了线程安全
            private static Singleton uniqueInstance = new Singleton();
            //Singleton类只有一个构造方法并且是被private修饰的,所以用户无法通过new方法创建该对象实例
            private Singleton(){}
            public static Singleton getInstance(){
                return uniqueInstance;
            }
        }
    

    所谓 “饿汉方式” 就是说JVM在加载这个类时就马上创建此唯一的单例实例,不管你用不用,先创建了再说,如果一直没有被使用,便浪费了空间,典型的空间换时间,每次调用的时候,就不需要再判断,节省了运行时间。

    2.2 懒汉式(非线程安全和synchronized关键字线程安全版本 )

    public class Singleton {  
          private static Singleton uniqueInstance;  
          private Singleton (){
          }   
          //没有加入synchronized关键字的版本是线程不安全的
          public static Singleton getInstance() {
              //判断当前单例是否已经存在,若存在则返回,不存在则再建立单例
    	      if (uniqueInstance == null) {  
    	          uniqueInstance = new Singleton();  
    	      }  
    	      return uniqueInstance;  
          }  
     }
    

    所谓 “ 懒汉式” 就是说单例实例在第一次被使用时构建,而不是在JVM在加载这个类时就马上创建此唯一的单例实例。

    但是上面这种方式很明显是线程不安全的,如果多个线程同时访问getInstance()方法时就会出现问题。如果想要保证线程安全,一种比较常见的方式就是在getInstance() 方法前加上synchronized关键字,如下:

          public static synchronized Singleton getInstance() {  
    	      if (instance == null) {  
    	          uniqueInstance = new Singleton();  
    	      }  
    	      return uniqueInstance;  
          }  
    

    我们知道synchronized关键字偏重量级锁。虽然在JavaSE1.6之后synchronized关键字进行了主要包括:为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升。

    但是在程序中每次使用getInstance() 都要经过synchronized加锁这一层,这难免会增加getInstance()的方法的时间消费,而且还可能会发生阻塞。我们下面介绍到的 双重检查加锁版本 就是为了解决这个问题而存在的。

    2.3 懒汉式(双重检查加锁版本)

    利用双重检查加锁(double-checked locking),首先检查是否实例已经创建,如果尚未创建,“才”进行同步。这样以来,只有一次同步,这正是我们想要的效果。

    public class Singleton {
    
        //volatile保证,当uniqueInstance变量被初始化成Singleton实例时,多个线程可以正确处理uniqueInstance变量
        private volatile static Singleton uniqueInstance;
        private Singleton() {
        }
        public static Singleton getInstance() {
           //检查实例,如果不存在,就进入同步代码块
            if (uniqueInstance == null) {
                //只有第一次才彻底执行这里的代码
                synchronized(Singleton.class) {
                   //进入同步代码块后,再检查一次,如果仍是null,才创建实例
                    if (uniqueInstance == null) {
                        uniqueInstance = new Singleton();
                    }
                }
            }
            return uniqueInstance;
        }
    }
    

    很明显,这种方式相比于使用synchronized关键字的方法,可以大大减少getInstance() 的时间消费。

    我们上面使用到了volatile关键字来保证数据的可见性,关于volatile关键字的内容可以看我的这篇文章:
    《Java多线程学习(三)volatile关键字》: https://blog.csdn.net/qq_34337272/article/details/79680771

    注意: 双重检查加锁版本不适用于1.4及更早版本的Java。
    1.4及更早版本的Java中,许多JVM对于volatile关键字的实现会导致双重检查加锁的失效。

    2.4 懒汉式(登记式/静态内部类方式)

    静态内部实现的单例是懒加载的且线程安全。

    只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance(只有第一次使用这个单例的实例的时候才加载,同时不会有线程安全问题)。

    public class Singleton {  
        private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
        }  
        private Singleton (){}  
        public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
        }  
    }   
    

    2.5 饿汉式(枚举方式)

    这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。 它更简洁,自动支持序列化机制,绝对防止多次实例化 (如果单例类实现了Serializable接口,默认情况下每次反序列化总会创建一个新的实例对象,关于单例与序列化的问题可以查看这一篇文章《单例与序列化的那些事儿》),同时这种方式也是《Effective Java 》以及《Java与模式》的作者推荐的方式。

    public enum Singleton {
    	 //定义一个枚举的元素,它就是 Singleton 的一个实例
        INSTANCE;  
        
        public void doSomeThing() {  
    	     System.out.println("枚举方法实现单例");
        }  
    }
    

    使用方法:

    public class ESTest {
    
    	public static void main(String[] args) {
    		Singleton singleton = Singleton.INSTANCE;
    		singleton.doSomeThing();//output:枚举方法实现单例
    
    	}
    
    }
    

    《Effective Java 中文版 第二版》

    这种方法在功能上与公有域方法相近,但是它更加简洁,无偿提供了序列化机制,绝对防止多次实例化,即使是在面对复杂序列化或者反射攻击的时候。虽然这种方法还没有广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。 —-《Effective Java 中文版 第二版》

    《Java与模式》

    《Java与模式》中,作者这样写道,使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制,并由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。

    2.6 总结

    我们主要介绍到了以下几种方式实现单例模式:

    • 饿汉方式(线程安全)
    • 懒汉式(非线程安全和synchronized关键字线程安全版本)
    • 懒汉式(双重检查加锁版本)
    • 懒汉式(登记式/静态内部类方式)
    • 饿汉式(枚举方式)

    参考:

    《Head First 设计模式》

    《Effective Java 中文版 第二版》

    【Java】设计模式:深入理解单例模式

    公众号

    如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。

    《Java面试突击》: 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本公众号后台回复 “Java面试突击” 即可免费领取!

    Java工程师必备学习资源: 一些Java工程师常用学习资源公众号后台回复关键字 “1” 即可免费无套路获取。

    我的公众号

    展开全文
  • PHP的单例模式实例

    千次阅读 2015-03-17 00:16:52
    只是举实例而已,目的是让我自己通过实例可以加深单例模式的理解!在此,仅供参考! 单例:可以简单的理解是通过个类,只能实例化单个对象,不能实例化多个对象! class e {  public $uname;  ...
  • 一对一实例:一个学生只有个身份证编号。 一对多实例:一个班级有多个学生。 多对多实例:多对多就是双向一对多,一个学生可以选择多门课,一门课也有多名学生。 1.一对多关系处理:我们以学生和班级之间的关系来...
  • 关系,关系模式,关系模型区别和联系

    万次阅读 多人点赞 2019-12-18 09:40:11
    关系模式是型,关系是值,关系模式对关系的描述 关系关系模式在某个时刻的状态或者内容,关系模式是静态的,稳定的,而关系是动态的,随时间不断变化的,因为关系操作在不断地更新着数据库中的数据 类似于面向对象...
  • 单例模式--确保个类只有实例,并提供个全局访问点。用处:有些对象其实我们只需要个,比方说:线程池,缓存,对话框,注册表,日志对象,显卡等设备的驱动程序的对象等。
  • 一对一:通过外键+unique唯一约束实现 #一对一 def get_bankcard(request):  bankcard = BankCard.objects.all()  return render(request,'get_bankcard.html',locals()) def get_person(request,pid):  #...
  • 这道题的思路是,我只让这个类通过个公有函数实例化对象,即可以将构造函数设置为私有成员函数。include using namespace std;class Single { public: static Single& SingleCreate() { if (m == NULL) { m =...
  • 分析他们之间的关系 1个订单只属于个用户 个用户可以拥有很多订单 2 个订单里面有多个订单项 个订单项只属于个订单 3 个订单项只属于个商品 个商品可以有很多个订单项 ...
  • 27.一对一,一对多,多对多关系表的各种骚操作

    万次阅读 多人点赞 2021-08-31 10:22:33
    (1)一对多表关系的数据的添加修改 ①学院表信息的插入: 常规方法是写个视图函数,在视图函数里添加插入数据的逻辑代码。但是这样的话——你得访问此视图函数对应的接口才能添加成功!岂不麻烦~ 所以,本博主...
  • 实例讲解TP5中关联模型

    万次阅读 2017-07-21 21:27:52
    关系型数据库中,表之间有一对一、一对多、多对多的关系。在 TP5 中,实现了ORM (Object Relational Mapping) 的思想,通过在模型中建立模型间的关联,实现建立表与表之间的关联。 二、文章中用到的表结构 image ...
  •  本来数据库一对一、一对多、多对多关系并不复杂,但是最近在理解的时候感觉又感觉...1、一对一关系实例  * 一个人对应一张身份证,一张身份证对应一个人 2、一对多关系实例  * 一个班级拥有多个学生,一个学生...
  • 很多情况下,我们在开发项目的过程中,都希望自己运行的某个部件只有实例, 比如我们天天用QT开发界面,QTCreate里帮助菜单下的关于Qt Create菜单,弹出来的关于对话框,在QTCreate运行过程中,不论单击多少次,...
  • 最近与位从事高校软件工程教育的同仁和挚友聊天,谈到如何提高学生的创新性思维,两人不免大肆吐槽一番,有谈到过目前高校教育体制、学校的培养方案等等等等,但是这些东东无论是作为我们老师还是学生,只有...
  • 数据库实例和数据库关系

    万次阅读 2016-12-01 16:08:19
    1、MySQL是单进程多线程(而Oracle等是多进程),也就是说MySQL实例在系统上表现就是个服务进程,即进程(通过多种方法可以创建多实例,再安装个端口号不同的Mysql,或者通过workbench来新建个端口号不
  • 2.关系模式 回答以下问题,完成实验内容: 1.设某汽车运输公司数据库中有三个实体集。是“车队”实体集,属性有车队号、车队名等;二是“车辆”实体集,属性有车牌照号、厂家、出厂日期等;三是“司机”实体集...
  •  在控制器中定义个方法来实例模型,使用的是普通方式实例化:创建部门控制器文件: 实例化代码: 实例化结果: 5.2、快速实例化方法上述的普通实例化方法虽然可以进行实例化操作,但是使用上比较麻烦,还...
  • 个类只实例化出个对象称为单例模式
  • 有A和B两个实例的RocketMQ,并不是集群关系。A的实例是服务器本地的RocketMQ,B的实例是阿里云上所购买的实例。在JAVA代码中,要做到往A发消息的时候也要往B推送消息。 光看需求,其实so easy。因为自己RocketMQ...
  • 1. 一对一的表,两表的属性实际上完全可以合并成一个表,共用一个主键即可; 2. 一对多的表,可以设中间关联表,也可以将关联表并入“多”这头;若设独立关联表,则可引入“多”这头的主键作为其主键,也可另立主键...
  • Yii2 模型实例

    千次阅读 2015-12-09 23:15:13
    Yii2.0 中,模型实例化方式有多种,如下:1. $model = new VPost(); 2. $model = VPost::findOne($id); 等价于 $customer = Customer::find()->where(['id' => 10])->one();3. $model =$this->findModel($id);...
  • 关联的对象¶当你在模型中定义个关联关系时(例如,ForeignKey、 OneToOneField 或ManyToManyField),该模型实例将带有个方便的API 来访问关联的对象。利用本页顶部的模型个Entry 对象e 可以通过...
  • 灰色预测模型及MATLAB实例

    万次阅读 多人点赞 2019-01-25 23:58:52
    灰色预测模型及MATLAB实例推荐下面的: https://www.cnblogs.com/somedayLi/p/9543202.html
  • 金融领域数据模型实例

    万次阅读 2018-02-14 10:41:16
    通用金融行业主题域模型通用金融行业概念模型主题域模型的设计原则:1 是商业模式的抽象2 以商业模式中关注的对象为划分依据3 内容完整且相对稳定4 每个主题域下一般都有个与之同名的主实体,围绕该主实体展开...
  • 设计模式综合实例分析之数据库同步系统(

    万次阅读 多人点赞 2013-03-14 01:00:46
    最近有很多朋友跟我聊到关于“在软件项目开发中如何合理使用设计模式”的问题,希望我...在此我也希望大家能够分享自己的一些设计模式使用心得和好的设计模式应用实例,可以整理份给我(可发送到邮箱:weiliu_chin
  • 关系模型名词解释 (1)关系模型:用二维表格结构表示实体集,外键表示实体间联系的... (3)关系实例:元组的集合称为关系实例关系即一张二维表格。 (4)属性:实体的个特征。在关系模型中,字段称为属性。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,309,489
精华内容 523,795
热门标签
关键字:

关系模型一对一的实例