Когда я изучил это некоторое время назад, я пришел к выводу, что нет единого правильного ответа.
Я закончил проверкой только свойства @Id
в equals()
и hashCode()
, так как это, казалось, работало лучше всего. (Мы не используем @NaturalId
s; вместо этого он мог бы работать с этим, но может быть безопаснее придерживаться @Id
.)
Я думаю, что единственная потенциальная проблема, с которой я столкнулся, была если новый экземпляр добавляется в коллекцию перед сохранением. На практике этого никогда не происходит в нашем проекте, и поэтому он работает хорошо. (Если это произойдет в вашем проекте, вы все равно можете найти это лучшим компромиссом, чтобы избежать проблем, когда сохраняются объекты появляются в коллекциях, что встречается гораздо чаще.)
Как и другие ответы указали, что если вы переопределяете equals()
, вы должны также переопределять hashCode()
, чтобы гарантировать, что равные объекты всегда имеют одинаковый хэш-код. (Первый пример вопроса соответствует этому, хотя, возможно, это немного сбивает с толку, когда два метода не проверяют все одинаковые поля.)
Кстати, в Котлине эти два метода становятся незначительно управляемыми: [ 1115]
override fun equals(other: Any?) = other === this
|| (other is MyEntity && entityId == other.entityId)
override fun hashCode() = entityId
(Еще один пример того, почему я люблю Котлина!)
Using time.sleep()
prevents twisted from doing its job. To make it work you can't use time.sleep()
, you must return control to twisted instead. The easiest way to modify your existing code to do that is by using twisted.internet.defer.inlineCallbacks
, which is the next best thing since sliced bread:
#!/usr/bin/env python
import time
from twisted.web import http
from twisted.internet import protocol
from twisted.internet import reactor
from twisted.internet import defer
def wait(seconds, result=None):
"""Returns a deferred that will be fired later"""
d = defer.Deferred()
reactor.callLater(seconds, d.callback, result)
return d
class StreamHandler(http.Request):
BOUNDARY = 'BOUNDARY'
def writeBoundary(self):
self.write("--%s\n" % (self.BOUNDARY))
def writeStop(self):
self.write("--%s--\n" % (self.BOUNDARY))
@defer.inlineCallbacks
def process(self):
self.setHeader('Connection', 'Keep-Alive')
self.setHeader('Content-Type', "multipart/x-mixed-replace;boundary=%s" % (self.BOUNDARY))
self.writeBoundary()
self.write("Content-Type: text/html\n")
s = "<html>foo</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeBoundary()
yield wait(2)
self.write("Content-Type: text/html\n")
s = "<html>bar</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeBoundary()
yield wait(2)
self.write("Content-Type: text/html\n")
s = "<html>baz</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeStop()
self.finish()
class StreamProtocol(http.HTTPChannel):
requestFactory = StreamHandler
class StreamFactory(http.HTTPFactory):
protocol = StreamProtocol
if __name__ == '__main__':
reactor.listenTCP(8800, StreamFactory())
reactor.run()
That works in firefox, I guess it answers your question correctly.
Причина, по-видимому, объяснена в FAQ для витая . Витой сервер на самом деле ничего не записывает в подчеркивающее соединение, пока поток реактора не будет запущен, в данном случае в конце вашего метода. Однако вы можете использовать реактор.doSelect (тайм-аут) перед каждым вашим сном, чтобы заставить реактор написать, что он имеет для соединения.
в этом случае в конце вашего метода. Однако вы можете использовать реактор.doSelect (тайм-аут) перед каждым вашим сном, чтобы заставить реактор написать, что он имеет для соединения. в этом случае в конце вашего метода. Однако вы можете использовать реактор.doSelect (тайм-аут) перед каждым вашим сном, чтобы заставить реактор написать, что он имеет для соединения.