1.索引的作用?和它的优点缺点是什么?
索引就一种特殊的查询表,数据库的搜索可以利用它加速对数据的检索。它很类似与现实生活中书的目录,不需要查询整本书内容就可以找到想要的数据。索引可以是唯一的,创建索引允许指定单个列或者是多个列。缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小。一般唯一、不为空、经常被查询的字段适合建索引
ps:Mysql里面有两种数据库引擎,一种是MyISAM,他用的是B树,行级锁。另一种Innodb 他是B+树,支持行锁表锁,而索引的话默认最多16个,因为不是创的越多越好,而b树b+树他们的数据结构来说,利用索引,就快速定位,不用的话,会一条一条查找,主键也是索引的另一种抽象。
2.请简述什么是集群?
服务器集群就是指将很多服务器集中起来一起进行同一种服务,在客户端看来就象是只有一个服务器。集群可以利用多个计算机进行并行计算从而获得很高的计算速度,也可以用多个计算机做备份,从而使得任何一个机器坏了整个系统还是能正常运行。一旦在服务器上安装并运行了群集服务,该服务器即可加入群集。群集化操作可以减少单点故障数量,并且实现了群集化资源的高可用性。
3.字符串中有重复的内容去重 例如:abbccccaaddaggb–>abvadagb
原理是: 循环一遍字符串,然后从头找每次循环一遍字符串,发现重复的去除,然后已经去重的字母,就不再加入循环了,比如第一个去完重,那就第二遍由第二个来遍历,直到字母都去完重
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("a");
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
System.out.println("没有去重前的数据为>>>" + list.toString());
for (int i = 0; i < list.size() - 1; i++) {
for (int j = list.size() - 1; j > i; j--) {
if (list.get(j).equals(list.get(i))) {
list.remove(j);
}
}
}
System.out.println("去重后的数据为>>>" + list.toString());
}
}
4.JAVA中使用final修饰符,对程序有哪些影响
● 修饰类
当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意 final 类中的所有成员方法都会被隐式地指定为final 方法。在使用 final 修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为 final类。
● 修饰方法
被final修饰的方法将不能被子类覆盖,主要用于:
把方法锁定,以防任何继承类修改它的含义。
在早期的Java实现版本中,会将final方法转为内嵌调用,所以效率能够提升。
● 修饰变量
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。当用 final 作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了
String底层是被final修饰的,所以是不可变字符串
5.什么叫对象持久化(object persistence),为什么要进行对象持久化?
持久化的对象,是已经存储到数据库或保存到本地硬盘中的对象,我们称之为持久化对象。为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。我们可以使用Java提供的序列化机制。
简单说对象序列化是将对象状态转换为可保持或传输的格式的过程。什么情况下需要序列化:
● 当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
● 当你想用套接字在网络上传送对象的时候;
● 当你想通过RMI传输对象的时候;
对象要实现序列化,是非常简单的,只需要实现Serializable接口就可以了。
ps:dubbo就需要先序列化,然后反序列化接收,然后redis和Hibernae都需要用到持久化概念
6. 脏读、幻读和不可重复读 + 事务隔离级别
脏数据在临时更新(脏读)中产生。事务A更新了某个数据项X,但是由于某种原因,事务A出现了问题,于是要把A回滚。但是在回滚之前,另一个事务B读取了数据项X的值(A 更新后),A回滚了事务,数据项恢复了原值。事务B读取的就是数据项X的就是一个“临时”的值,就是脏数据。
丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的;
==脏读:==就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
ps:😋别人修改金额1000,但是没提交事务回滚了,第二个人读取到了修改完金额1000
不可重复读:一个事务读进一条记录,另一个事务更改了这条记录并提交完毕,这时候第一个事务再次读这条记录时,它已经改变了
ps:😋一个人读自己的钱500,正要再存500的时候,再读一遍发现钱只剩一百了,因为,第二个人他取了400然后提交了事务,但是自己却不知道第一遍读的500是正确的还是这个100是正确,两次值不一样,最好办法是一个事务加锁,处理完,其他人才能进事务。
==幻读:==是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
ps😋幻读和不可重读差不多一样的问题,只是幻读的重点在于新增或者删除,不可重复读的重点是修改 ,解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
mysql默认的事务隔离级别为repeatable-read不是隔离级别越高越好,要考虑到效率问题,结合实际业务场景进行使用
7.Mybatis中#和$的区别?
● #相当于对数据加上双引号,$相当于直接显示数据(#会拦截sql先加上"",作用有点像parestatement预编译)
● #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by#user_id#,如果传入的值是111,那么解析成sql时的值为order by"111",如果传入的值是id,则解析成的sql为order by “id”.
● user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id,如果传入的值是id,则解析成的sql为order by id.
这个太容易sql注入了,不建议使用
● #方式能够很大程度防止sql注入,$方式无法防止Sql注入。
● $方式一般用于传入数据库对象,例如传入表名.
ps✴️ 接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。
8.JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的
● 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,使用数据库链接池可解决此问题。解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
● Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
● 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。解决: Mybatis 自动将 java 对象映射至 sql 语句。
● 对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对象解析比较方便。解决:Mybatis 自动将 sql 执行结果映射至 java 对象。
说白了,mybatis是一个优秀的orm框架,自动将pojo对象与数据库进行映射关联。
9.使用MyBatis的mapper接口调用时有哪些要求?
● Mapper接口方法名和mapper.xml中定义的每个sql的id相同
● Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
● Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
● Mapper.xml文件中的namespace即是mapper接口的类路径。
ps:他底层是将mapper的namespace+id方法名当作一个map的key进行存起来,如果已经有存的直接返回这个,如果没有,就会先存起来,而且通过namespace+方法名很容易找到那个mapper类