面试题每日三问

1、

找厂商开发了一个系统,给了数据库脚本、包只有class文件,部署完成后想要监测价格表里商品价格变化,货物上下架情况等,怎样在不找原厂商的情况下做到?
答:监测数据表数据变化情况,短时间内用快照。长期的可以给这张表建立触发器,如果有变化时把变化的数据存到另外的表里。
这是我查到的,有补充的没有?

2、

springboot怎样读取配置文件的,比如我想加载另外的数据源就要读取单独的数据库配置文件?
先说点其他的。如果是默认的application.propreties里,想要在javabean里绑定里面值可以用下面的方法
在这里插入图片描述
再来说加载指定配置文件,比如弄两个数据源配置文件,在数据源类里可以用注解@PropertySource来指定,比如
在这里插入图片描述
base数据源配置实体类
在这里插入图片描述
然后配置数据源`

package com.stu.config;
 
import javax.sql.DataSource;
 
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 
import com.alibaba.druid.pool.DruidDataSource;
 
@Configuration
//只从com.stu.dao包下读取dao文件,并且该报下的dao使用本datasource
@MapperScan(basePackages = "com.stu.dao", sqlSessionTemplateRef = "baseSqlSessionTemplate")
public class DB1Configuration {
	@Bean(name = "baseDataSource")
    //对于多数据源,必须制定primary,否则报错有2个datasource,并且,只能制定一个primary
    @Primary
    //从DB1Config从获取配置信息
    public DataSource setDataSource(DB1Config dbc) {
		DruidDataSource ds = new DruidDataSource();
		ds.setUrl(dbc.getUrl());
		ds.setUsername(dbc.getUsername());
		ds.setPassword(dbc.getPassword());
		ds.setDriverClassName(dbc.getDriver());
		return ds;
    }
 
    @Bean(name = "baseSqlSessionFactory")
    @Primary
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("baseDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //指定mapper.xml文件存放位置
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/base/*.xml"));
        return bean.getObject();
    }
 
    @Bean(name = "baseSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("baseSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

参考来自
SpringBoot读取自定义properties配置文件 + 多数据源配置
总结:用注解@ConfigurationProperties(prefix = “person”)
可以绑定默认的配置文件里的值。
如果想要加载自己指定的配置文件可以用注解@PropertySource
想绑定属性名可以用@value注解
@Value("${my.name}")
private String myName;

2021-02-22

1、ArrayList的内部实现机制是什么?
答:先看它的构造方法源码,三个构造方法。

 // ArrayList无参构造函数。默认容量是10。    
    public ArrayList() {    
        this(10);    
    }   

 // ArrayList带容量大小的构造函数。    
    public ArrayList(int initialCapacity) {    
        super();    
        if (initialCapacity < 0)    
            throw new IllegalArgumentException("Illegal Capacity: "+    
                                               initialCapacity);    
        // 新建一个数组    
        this.elementData = new Object[initialCapacity];    
    }     

    // 创建一个包含collection的ArrayList    
    public ArrayList(Collection<? extends E> c) {    
        elementData = c.toArray();    
        size = elementData.length;    
        if (elementData.getClass() != Object[].class)    
            elementData = Arrays.copyOf(elementData, size, Object[].class);    
    }

所以ArrayList的本质是一个Object数组。
基本的方法有add(),remove(),size(),clear()等。
不传参数是默认长度为10的数组(初始容量为0,添加第一个元素时变为10个容量),或者传指定个数,或者创建一个包含collection的ArrayList
如果不传参数默认为10个长度,当容量不够是就需要扩容
ensureCapacity方法将整个数组Copy到新的数组中,这里发生第一次Copy,把原来的数组Copy到一个大约1.5倍大的新的数组里
具体的扩容机制见
https://blog.csdn.net/qq_26542493/article/details/88873168

2、事务的特性,一个事务里同时有查询和修改合适吗?
答:ACID是衡量事务的四个特性:

原子性(Atomicity,或称不可分割性)
一致性(Consistency)
隔离性(Isolation)
持久性(Durability)

对应的可能出现的情况:
1.脏读:一个事务读取到另一个事务未提交的数据。

2.不可重复读:在同一个事务中,重复执行相同的sql,查询到的结果却不相同。

3.幻读:当某个事务读取范围内的数据时,另一个事务在该范围内插入数据,之前的事务再次读取范围内的数据时,会引发幻读。解释一下:例如在一个事务A中,执行查询,得到的结果集是10条,此时另一个事务B恰好执行了插入操作,事务A再次去查询的时候,却发现结果集有11条,貌似出现幻觉。

事务的隔离级别:
事务的隔离级别大致分为四个等级,Read uncommitted(读未提交)、Read committed(读已提交)、Repeatable read(可重复读)、Serializable(串行化),接下来对这四个隔离级别进行解释,并且说明他们分别解决了什么样的问题?(脏读、不可重复读、幻读)
读未提交:导致脏读
读已提交:解决脏读,导致不可重复读
可重复读:解决不可重复读,导致幻读
串行化:能解决所有,但是性能太低
在这里插入图片描述
3、mybatis怎样传递多个参数?
参考
https://www.jb51.net/article/184326.htm
https://www.cnblogs.com/knowledgesea/p/11212842.html
其中

 <select id=" selectUser" resultMap="BaseResultMap">
   select * from user_user_t where user_name = #{userName,jdbcType=VARCHAR} and user_area=#{userArea,jdbcType=VARCHAR}
 </select>

也可以用#{0},#{1}这样按参数顺序指定,但是不直观,但是按上面这种形式又比较繁琐,所以参数少用@param注解法,参数多用map传参法,当然实际中最多用的是javabean传参法。

2021-02-23

1、spring AOP 的原理?实现方式?

答:
AOP即横向重复,纵向抽取,把多个需要重复的代码抽取出来减少工作量,比如事务的开启提交、日志记录权限控制等。
名词解释如下图

在这里插入图片描述
其中连接点是可以被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。拦截点被拦截增强后就成了切入点。

通知(即增强的代码逻辑):共有五种类型
前通知:方法执行之前,method:增强执行的方法
后通知:方法执行之后,又称最终通知,无论如何都执行
返回后通知:成功返回后,有异常时不执行
异常通知:发生异常后,只有异常抛出时才执行,不能try…catch异常
环绕通知:在方法的执行前后进行一些增强,在方法的执行前后进行一些增强 =前通知+返回后通知

spring AOP 的实现原理:
使用动态代理和cglib代理相结合的方式,其中动态代理需要目标对象必须实现接口,如果没有实现接口则必须使用cglib代理,而cglib代理的原理是要继承目标对象,所以目标对象必不能被final修饰,否则不可行。
AOP实现方式:
1、基于xml配置实现
spring-mvc.xml

 	<!-- 使用xml配置aop -->
	<!-- 强制使用cglib代理,如果不设置,将默认使用jdk的代理,但是jdk的代理是基于接口的 -->
	<aop:config proxy-target-class="true" />  
	<aop:config>
	<!--定义切面-->
 	<aop:aspect id="logAspect" ref="logInterceptor">
 	<!-- 定义切入点 (配置在com.gray.user.controller下所有的类在调用之前都会被拦截)-->
  	<aop:pointcut expression="execution(* com.gray.user.controller.*.*(..))" id="logPointCut"/>
  	<!--方法执行之前被调用执行的-->
  	<aop:before method="before" pointcut-ref="logPointCut"/><!--一个切入点的引用-->
 	<aop:after method="after" pointcut-ref="logPointCut"/><!--一个切入点的引用-->
 	</aop:aspect>
	</aop:config>

LogInterceptor.java

package com.gray.interceptor;
 
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
@Component
public class LogInterceptor {
	private final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
	public void before(){
		logger.info("login start!");
	}
	
	public void after(){
		logger.info("login end!");
	}
}

要加入日志管理逻辑的地方,即配置的切入点的地方

@RequestMapping("/dologin.do") //url,这个类在com.gray.user.controller.*.*(..)下
public String dologin(User user, Model model){
	logger.info("login ....");
	String info = loginUser(user);
	if (!"SUCC".equals(info)) {
		model.addAttribute("failMsg", "用户不存在或密码错误!");
		return "/jsp/fail";
	}else{
		model.addAttribute("successMsg", "登陆成功!");//返回到页面说夹带的参数
		model.addAttribute("name", user.getUsername());
		return "/jsp/success";//返回的页面
	}
  }

在这里插入图片描述
2、基于注解的实现
需要先打开支持注解开关

    <aop:aspectj-autoproxy proxy-target-class="true">
    </aop:aspectj-autoproxy>

LogInterceptor.java类

@Aspect//这两个注解都很重要
@Component
public class LogInterceptor {
	private final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
	@Before(value = "execution(* com.gray.user.controller.*.*(..))")
	public void before(){
		logger.info("login start!");
	}
	@After(value = "execution(* com.gray.user.controller.*.*(..))")
	public void after(){
		logger.info("login end!");
	}
}

这样com.gray.user.controller下的方法执行时就会被before和after两个方法截到
在这里插入图片描述
参考链接

2、hashmap和linkedhashmap有什么区别

答:hashMap根据键的HashCode值存储数据,可以根据键直接获取它的值,具有很快的访问速度,遍历时候的顺序是完全随机的。HashMap只允许一个键为Null,允许多个值为Null。线程不安全,多个线程同时写HashMap可能导致数据不一致。

LinkedHashMap是HashMap的一个子类,保存了记录的插入顺序,与HashMap的随机遍历不同,在用Iterator遍历的时候,先得到的记录肯定是先插入的。
遍历速度会比HashMap慢,不过有一种情况例外: 当HashMap的容量很大,实际数据很少时 , 因为HashMap的遍历速度和它的容量有关,而LinkedHashMap只跟实际数据量有关。

2021-03-01

1、一个表有大量的读和写操作怎么办?

答:创建存储过程和建立合适的索引

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值