什么是单例模式
单例模式:
指在整个应用中只有一个实例
满足条件:
1.构造方法私有化,为了避免外部通过new来创建对象。
2.提供静态方法,用于返回本类的一个实例。
3.在类的内部,声明一个本类的实例,如果实例为null,则创建,否则返回。
实现方式:
1.饱汉式:类的实例只有调用时才会创建。
2.饿汉式:类的实例在类的加载时直接创建。
记得引入相关依赖:mybatis mysql junit
创建SqlSessionFactoryUtils类(单例模式:饱汉式)
public class SqlSessionFactoryUtils {
/**
* 声明本类的实例
*/
private static SqlSessionFactoryUtils instance = null;
/**
* 构造方法私有化
*/
private SqlSessionFactoryUtils(){
}
/**
* 提供静态方法
* 饱汉式:类的实例只有类在调用的时才会创建
* @return 本类的实例
*/
public static SqlSessionFactoryUtils getInstance(){
if (null == instance){
instance = new SqlSessionFactoryUtils();
}
return instance;
}
}
使用测试类来测试
@Test
public void testInstance(){
SqlSessionFactoryUtils s1 = SqlSessionFactoryUtils.getInstance();
SqlSessionFactoryUtils s2 = SqlSessionFactoryUtils.getInstance();
System.out.println(s1 == s2);
}
执行结果为true
执行流程
在饱汉模式下,实例在首次使用时创建,并在后续调用时重复使用。
执行流程如下:
1.首次调用getInstance()方法。
2.当前instance变量为null,进入if语句块。
3.在if语句块中,创建SqlSessionFactoryUtils的新实例,并将其赋值给instance变量。
3.返回instance对象。
4.后续再次调用getInstance()方法。
5.当前instance变量不为null,直接返回之前创建的instance对象。
通过这种方式,可以确保在整个应用程序生命周期中,只创建一个SqlSessionFactoryUtils的实例,供全局使用。这种单例模式的实现方式适用于无需考虑多线程并发访问的情况下。如果需要考虑线程安全性,可以在getInstance()方法中添加同步控制,或者使用其他单例模式的实现方式,如双重检查锁定模式、静态内部类模式等。
创建SqlSessionFactoryUtils2类(单例模式:饿汉式)
public class SqlSessionFactoryUtils2 {
/**
* 声明本类的实例
*/
private static SqlSessionFactoryUtils2 instance = null;
/**
* 静态代码块,类在加载的时候首先执行静态代码块
* 饿汉式:类的实例在类的加载时直接创建。
*/
static {
instance = new SqlSessionFactoryUtils2();
}
/**
* 构造方法私有化
*/
private SqlSessionFactoryUtils2(){}
/**
* 提供静态方法,返回本类的实例
*/
public static SqlSessionFactoryUtils2 getInstance(){
return instance;
}
}
使用测试类来测试
@Test
public void testInstance2(){
SqlSessionFactoryUtils2 s1 =SqlSessionFactoryUtils2.getInstance();
SqlSessionFactoryUtils2 s2 =SqlSessionFactoryUtils2.getInstance();
System.out.println(s1 == s2);
}
执行结果为true
在饿汉模式下,实例在类加载时就被创建,无论是否被使用。
执行流程如下:
1.类加载时,创建SqlSessionFactoryUtils2的静态变量instance,并将其实例化。
2.静态变量instance被赋初值,即创建了SqlSessionFactoryUtils2的实例。
3.调用getInstance()方法。
4.直接返回之前创建的instance对象,由于实例已经在类加载时被创建,因此无需再次创建。
由于在类加载时就创建了实例,所以无论后续是否使用该实例,都会存在于内存中。这种实现方式适用于在应用程序启动时就需要创建好的实例,且无需考虑多线程并发访问的情况。需要注意的是,饿汉式实现可能会造成资源浪费,因为实例在类加载时就被创建,无论是否被使用。因此,在某些场景下可能更适合使用懒汉式实现方式。
附加小案例:使用单例模式的饿汉式封装Mybatis的 SqlSessionFactory会话工厂
创建SqlSessionFactory会话工厂封装类 FactoryUtils
public class FactoryUtils {
/**
*声明本来的实例
*/
private static FactoryUtils instance;
private static SqlSessionFactory sqlSessionFactory;
/**
*静态代码块
*/
static {
instance = new FactoryUtils();
}
/**
*构造方法
*/
private FactoryUtils(){
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
InputStream is = this.getClass().getClassLoader().getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = builder.build(is);
}
/**
*
* @return 返回会话工厂
*/
public static SqlSessionFactory sqlSessionFactory(){
return sqlSessionFactory;
}
}
代码执行流程如下:
1.创建FactoryUtils类。
2.声明静态变量instance和sqlSessionFactory。
3.在静态代码块中,将instance实例化为FactoryUtils的新实例。
4.在构造方法中,创建SqlSessionFactoryBuilder对象,用于构建SqlSessionFactory实例。
5.使用类加载器获取mybatis-config.xml配置文件的输入流。
6.使用SqlSessionFactoryBuilder的build()方法,根据配置文件的输入流创建SqlSessionFactory实例,赋值给sqlSessionFactory变量。
7.提供静态方法sqlSessionFactory(),用于返回静态变量sqlSessionFactory。
基础的mybatis-config.xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 开启日志 -->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--更改value值,或者自己加入db.properties文件配置数据库链接-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--用来指定Mapper.xml配置文件的位置,根据需求更改-->
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
mybatis-config.xml详细配置请参考mybatis官网:https://mybatis.org/mybatis-3/zh/index.html
创建Mapper接口
public interface DbMapper {
@Select("select * from t_student where id = #{id}")
public Map getById(int id);
}
创建TestStudent测试类
public class TestStudent {
@Test
public void getById(){
try (SqlSession sqlSession = FactoryUtils.sqlSessionFactory().openSession()){
DbMapper dbMapper = sqlSession.getMapper(DbMapper.class);
System.out.println(dbMapper.getById(2));
}
}
}
测试运行结果如图: